Проверьте, существует ли в каталоге файл определенного типа / расширения

84

Как бы вы сказали, присутствуют ли файлы с определенным расширением в каталоге с помощью bash?

Что-то вроде

if [ -e *.flac ]; then 
echo true; 
fi 
Wurlitzer
источник

Ответы:

104
#!/bin/bash

count=`ls -1 *.flac 2>/dev/null | wc -l`
if [ $count != 0 ]
then 
echo true
fi 
Джереми Вейр
источник
9
Привет, Томас, как насчет того, чтобы добавить лучшее решение вопроса вместо простого отрицательного голоса.
JeremyWeir
8
Также Томас, ваш пример того, почему не использовать его, использует ls -l, мой ответ используетls -1
JeremyWeir
10
И этот ответ не анализирует вывод, он просто подсчитывает выводимые строки, и я почти уверен, что даже если в имени файла есть странные символы, ls -1он будет печатать одну строку для каждого файла
JeremyWeir
2
Подсчет строк - это разбор. И он вернет неправильное число, если какие-либо файлы содержат \n(и да, это действительно в именах файлов).
Марсельм
1
Скажите, пожалуйста, какой магический символ должен быть в имени файла, чтобы счетчик строк был нулевым?
старшина
27
#/bin/bash

myarray=(`find ./ -maxdepth 1 -name "*.py"`)
if [ ${#myarray[@]} -gt 0 ]; then 
    echo true 
else 
    echo false
fi
wkl
источник
5
Это хорошо, потому что вы действительно можете что- то сделать с файлами после того, как их найдете.
ephsmith
+1 для заключения подоболочки с командой find в скобки, чтобы сделать myarray переменной массива. В противном случае, если find не вернет результат, ${#myarray[@]}равный 1
shaffooo
также можно упростить, используя ls -1 *.pyвместо find
JrBenito
Если в имени любого из файлов есть пробел, то один экземпляр будет засчитан как два.
Джон Гриффит
16

При этом используется ls (1), если файлов flac не существует, ls сообщает об ошибке, и сценарий завершается; в противном случае сценарий продолжается, и файлы могут быть обработаны

#! /bin/sh
ls *.flac  >/dev/null || exit
## Do something with flac files here
фрейзер
источник
4
Для дополнительной тишины перенаправьте также 2> & 1.
Джаспер
6
Версия if:if ls *.flac >/dev/null 2>&1; then ... fi;
Джозайя Йодер
9
shopt -s nullglob
if [[ -n $(echo *.flac) ]]    # or [ -n "$(echo *.flac)" ]
then 
    echo true
fi
Деннис Уильямсон
источник
4

Вы должны быть осторожны, какой флаг вы добавляете в свое ifутверждение и как он соотносится с желаемым результатом.

Если вы хотите проверять только обычные файлы, а не другие типы записей файловой системы, вам нужно изменить скелет кода на:

if [ -f file ]; then
echo true;
fi

Использование -fограничивается ifобычными файлами, тогда как -eоно более обширное и соответствует всем типам записей файловой системы. Конечно, есть и другие варианты, такие как -dкаталоги и т. Д. См. Http://tldp.org/LDP/abs/html/fto.html для хорошего списка.

Как указано в @msw, test(т.е. [) задохнется, если вы попытаетесь передать ему более одного аргумента. Это может произойти в вашем случае, если glob for *.flacвернул более одного файла. В этом случае попробуйте обернуть ifтест в цикл, например:

for file in ./*.pdf
do
    if [ -f "${file}" ]; then
    echo 'true';
    break
    fi
done

Таким образом, вы выберете breakпервый экземпляр нужного вам расширения файла и сможете продолжить работу с остальной частью скрипта.

dtlussier
источник
1
except test(aka [) жалуется, если шаблон расширяется до более чем одного файла: «ожидается бинарный оператор» или «слишком много аргументов»
msw
1
@msw - спасибо, даже не подумал об этой проблеме. Я попытался изменить свой ответ, чтобы учесть это.
dtlussier
Вы должны заключить переменную в кавычки, т.е. использовать "$file", потому что имя файла может содержать некоторые неправильные символы, такие как пробелы или звездочки.
Роман Чепляка 04
3
#!/bin/bash
files=$(ls /home/somedir/*.flac 2> /dev/null | wc -l)
if [ "$files" != "0" ]
then
echo "Some files exists."
else
echo "No files with that extension."
fi
Руэль
источник
3

Лучшее решение (if [ -e *.flac ];)не сработало для меня, дав:[: too many arguments

if ls *.flac >/dev/null 2>&1; тогда это будет работать.

Эрик Буйтенхейс
источник
3

Вы можете использовать -f, чтобы проверить, существуют ли файлы определенного типа:

#!/bin/bash

if [ -f *.flac ] ; then
   echo true
fi 
Узи
источник
Это работает, но вы закапываете lede - причина, по которой он работает, заключается в том, что одинарная скобка [(в отличие от более распространенной [[) не предотвращает подстановку.
Адриан Петреску,
2
   shopt -s nullglob
   set -- $(echo *.ext)
    if [ "${#}" -gt 0 ];then
      echo "got file"
    fi
призрачная собака74
источник
Это не правильно. Во-первых, вы, вероятно, имели в виду -geвместо -gt, потому что иначе ваш код не обнаружит один файл. Во-вторых, если нет файлов, соответствующих шаблону, любая соответствующая оболочка оставит строку *.extнетронутой, так что вы все равно получите один «результат».
Роман Чепляка 04
$ # - это 1 для одного файла и 0 для файлов без файлов.
frayser
1

только bash:

any_with_ext () ( 
    ext="$1"
    any=false
    shopt -s nullglob
    for f in *."$ext"; do
        any=true
        break
    done
    echo $any 
)

if $( any_with_ext flac ); then
    echo "have some flac"
else 
    echo "dir is flac-free"
fi

Я использую круглые скобки вместо фигурных скобок, чтобы гарантировать, что используется подоболочка (не хочу, чтобы ваши текущие nullglobнастройки были искажены ).

Гленн Джекман
источник
1

Вот решение, в котором не используются внешние команды (т.е. нет ls), а вместо этого используется функция оболочки. Протестировано в bash:

shopt -s nullglob
function have_any() {
    [ $# -gt 0 ]
}

if have_any ./*.flac; then
    echo true
fi

Функция have_anyиспользует $#для подсчета своих аргументов, а [ $# -gt 0 ]затем проверяет, есть ли хотя бы один аргумент. Использование ./*.flacвместо вместо простого *.flacвызова to have_anyпозволяет избежать проблем, вызванных файлами с такими именами, как --help.

Йохен
источник
1

Для завершения с помощью zsh:

if [[ -n *.flac(#qN) ]]; then
  echo true
fi

Это указано в конце раздела « Условные выражения » в руководстве по zsh. Поскольку [[отключает подстановку имени файла, нам нужно принудительно генерировать имя файла, используя (#q)в конце строки подстановки, затем Nфлаг ( NULL_GLOBпараметр), чтобы сгенерированная строка была пустой в случае отсутствия совпадения.

Исо
источник
1

Вот довольно простое решение:

if [ "$(ls -A | grep -i \\.flac\$)" ]; then echo true; fi

Как видите, это всего лишь одна строка кода, но она работает достаточно хорошо. Он должен работать как с bash, так и с posix-совместимой оболочкой, такой как dash. Он также нечувствителен к регистру и не заботится о том, какие типы файлов (обычные, символические ссылки, каталоги и т. Д.) Присутствуют, что может быть полезно, если у вас есть некоторые символические ссылки или что-то в этом роде.

TSJNachos117
источник
Мне это нравится, потому что ls -AR выполняет рекурсивный поиск. хорошо подходит для поиска содержимого zip-архивов после распаковки.
Джастин Кресс
0

Я пробовал это:

if [ -f *.html ]; then
    echo "html files exist"
else
    echo "html files dont exist"
fi

Я без проблем использовал этот фрагмент кода для других файлов, но для файлов html получил ошибку :

[: too many arguments

Затем я попробовал решение подсчета @ JeremyWeir, которое сработало для меня.

Имейте в виду, что вам придется сбросить счетчик, если вы делаете это в цикле:

count=$((0))
GChuf
источник
0

Это должно работать в любой подобной оболочке:

if [ "$(find . -maxdepth 1 -type f | grep -i '.*\.flac$')" ]; then
    echo true
fi

Это также работает с GNU find, но IDK, если он совместим с другими реализациями find:

if [ "$(find . -maxdepth 1 -type f -iname \*.flac)" ]; then
    echo true
fi
TSJNachos117
источник