2014-11-01 1 views
1

Я хочу проверить, нет ли файлов .txt в текущем каталоге. Как это сделать в стандартной оболочке?Shell: как проверить, нет ли файлов .txt в каталоге?

Требования: (? В одной строке без кратных функций)

  • должен работать с любым ш (не только Баш)
  • Должно быть эффективным

С точки зрения простоты, он должен как можно ближе к чему-то вроде:

#! /bin/sh 

[ -f ./*.txt ] || echo "Not found!" 

ответ

1

Использование find может быть хорошим выбором здесь:

#!/bin/sh 

res= 
res=$(find . -maxdepth 1 -name '*.txt' -type f -print -quit) 

[ -n "$res" ] || echo 'Not found!' 

, который может быть сокращен до:

#!/bin/sh 

[ -n "$(find . -maxdepth 1 -name '*.txt' -type f -print -quit)" ] || echo 'Not found!' 

Преимущество этого в том, что нет оболочки шариков , и find завершает работу, как только *.txtфайл найден. Вы не получите Список аргументов слишком длинный ошибок, если их слишком много .txt файлов, и в этом случае это будет быстрее.

Кроме того, с -type f мы уверены, что имеем дело только с файлами. Многие ответы, связанные с глобусами, потерпят неудачу, если нет файлов .txt, но каталог по имени whatever.txt.


Как @chepner состояний в комментарии (спасибо!), -maxdepth и -quit не определены POSIX, так что это решение не является портативным (-printf не определен POSIX либо, но это тривиально исправить, чтобы заменить -printf по -print).

Чтобы зафиксировать переключатель -quit, мы будем использовать grep следующим образом:

find . -name '*.txt' -type f | grep -q . || echo 'Not found!' 

Как только grep считывает символ, он выходит, закрывая трубку и find уйдет тоже. Это будет рекурсивно в подкаталогах (это может быть желаемое поведение).

В противном случае, если вы не хотите рекурсии:

find . -type d \! -name . -prune \! -type d -o -name '*.txt' -type f | grep -q . || echo 'Not found!' 
+2

Имейте в виду, что '-printf' и' -maxdepth' не являются частью стандарта POSIX для 'find', если вам нужно, чтобы это было полностью переносимым. – chepner

+0

@чепнер спасибо! пост отредактирован соответствующим образом. –

1

Попробуйте следующее:

if ls ./*.txt > /dev/null 
then 
    echo "File Exists" 
else 
    echo "File Doesn't exists" 
fi 
1
(echo *.txt | grep -q '*') && echo not found 
+0

'touch 'hello * world.txt''. Сюрприз. –

+0

Правильная идея, неправильное выполнение. 'f = $ (echo * .txt); case $ f в "* .txt") echo not found ;; *) найденное эхо ;; esac' –

0
[ `printf *.txt` = '*.txt' ] 

возвращает ответ на вопрос OP

Edit: явно лучше, чем неявное

[ `printf *.txt` = '*.txt' ] && echo "Not found!" 

Редактировать # 2, спасибо gniourf_gniourf

([ `printf *.txt` != '*.txt' ] || [ -f '*.txt' ]) && echo yes || echo no 
+0

Это не удается, если есть уникальный файл 'txt' с именем' * .txt'. –

+0

Конечно, вы правы, я намеревался упомянуть, но ... спасибо. – gboffi

+0

О, забыл упомянуть еще раз! моя последняя попытка не удалась, если есть каталог с именем 'whatever.txt'. – gboffi

1

После

(for f in *.txt; do [ -f "$f" ] && exit; done; exit 1) 

$? будет 0, если *.txt соответствует ничего, 1 в противном случае.

(Предполагается, что *.txt трактуется буквально, когда она не соответствует ничего, что должно быть истинным в POSIX оболочки, но может быть ложным, если, например, вы используете bash и вариант nullglob установлен.)

(Update : Я включил предложения gniourf_gniourf для обработки нерегулярных файлов, которые могут совпадать с *.txt.)

+0

Я думаю, вы имеете в виду '(for f in * .txt; do [-f" $ f "] & & exit; done)'. В противном случае, если каталог, заканчивающийся на '.txt', появится перед существующим файлом' .txt' в расширении glob, ваша команда ошибочно вернет сбой. –

+0

Чтобы убедиться в своем предположении, просто добавьте 'exit 1' после ключевого слова' done'. –

+0

'exit' без аргументов намеренно. Я хочу, чтобы статус выхода '[' сохранялся после завершения цикла. Вначале я использовал 'break', но всегда устанавливал' $? 'На 0. Вместо этого я использую' exit', чтобы вырваться из подоболочки с любым ''? 'Из предыдущей ('' ') команды. (С вашим первым предложением цикл будет перебирать все сопоставимые файлы, а не завершаться, как только он определяет, соответствует ли '* .txt' любым файлам или нет.) (Я действительно, у которого' bash' был какой-то 'glob' оператор.) – chepner

Смежные вопросы