Я пытаюсь проверить, существует ли файл, но с подстановочным знаком. Вот мой пример:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
Я тоже пробовал без двойных кавычек.
Я пытаюсь проверить, существует ли файл, но с подстановочным знаком. Вот мой пример:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
Я тоже пробовал без двойных кавычек.
Обновление: для сценариев bash наиболее прямой и эффективный подход:
if compgen -G "${PROJECT_DIR}/*.png" > /dev/null; then
echo "pattern exists!"
fi
Это будет работать очень быстро даже в каталогах с миллионами файлов и не требует новой подоболочки.
Самый простой - полагаться на возвращаемое значение ls
(оно возвращает ненулевое значение, если файлы не существуют):
if ls /path/to/your/files* 1> /dev/null 2>&1; then
echo "files do exist"
else
echo "files do not exist"
fi
Я перенаправил вывод ls
, чтобы сделать его полностью бесшумным.
РЕДАКТИРОВАТЬ: поскольку этому ответу уделялось немного внимания (и очень полезные замечания критиков в виде комментариев), вот оптимизация, которая также полагается на расширение глобуса, но избегает использования ls
:
for f in /path/to/your/files*; do
## Check if the glob gets expanded to existing files.
## If not, f here will be exactly the pattern above
## and the exists test will evaluate to false.
[ -e "$f" ] && echo "files do exist" || echo "files do not exist"
## This is all we needed to know, so we can break after the first iteration
break
done
Это очень похоже на ответ @ grok12, но позволяет избежать ненужной итерации по всему списку.
dash
), установленном в /bin/sh
в Debian и Ubuntu, &>
, похоже, отбрасывает код выхода, и это нарушает это решение. Обходной путь - вместо этого перенаправить с помощью > /dev/null 2>&1
.
- person qerub; 20.11.2011
ls
может работать довольно медленно в каталоге с большим количеством файлов (вероятно, из-за сортировки). По крайней мере, вы можете отключить сортировку с помощью -U
.
- person musiphil; 22.06.2012
ls
.
- person Costi Ciudatu; 27.09.2014
for f in /path/to/your files*
интерпретируется как два аргумента, /path/to/your
и files*
? Я пробовал заключать в двойные кавычки, но это не сработало (файл никогда не находит, даже если он есть).
- person Izzy; 14.12.2014
*
снаружи: for f in "/path/to/your files"*
должно работать.
- person Costi Ciudatu; 14.12.2014
for
циклов, ни каких-либо внешних инструментов, и работает с именами файлов, содержащими пробелы: stackoverflow.com/ a / 40808284/566849
- person Fabio A.; 25.11.2016
glob
. Например, один из серверов unix на моей работе не поддерживает glob
.
- person Sometowngeek; 17.09.2018
set -e
(часто включается в системах сборки, чтобы bash немедленно завершал работу при ошибках). В этом случае сценарий может нежелательно дать сбой при обнаружении цикла for.
- person Jonathan Komar; 04.11.2019
compgen -G
, похоже, не совсем поддерживает расширенные шаблоны глобусов. Не работает с compgen -G "*.{ts,go,json}"
. То есть логика подстановки -G и логика подстановки фактическая не всегда одинаковы (по крайней мере, без дополнительной заботы?). Кажется хрупким.
- person Dr. Jan-Philip Gehrcke; 08.12.2020
Если в вашей оболочке есть параметр nullglob и он включен, шаблон подстановки, не соответствующий файлам, будет полностью удален из командной строки. Это приведет к тому, что ls не увидит аргументов пути, выведет список содержимого текущего каталога и завершится успешно, что неверно. GNU stat, который всегда терпит неудачу, если не заданы аргументы или аргумент, указывающий на несуществующий файл, был бы более надежным. Кроме того, оператор перенаправления &> - это треп.
if stat --printf='' /path/to/your/files* 2>/dev/null
then
echo found
else
echo not found
fi
Еще лучше GNU find, который может обрабатывать поиск с использованием подстановочных знаков внутренне и завершать работу, как только найдет один подходящий файл, вместо того, чтобы тратить время на обработку потенциально огромного их списка, расширенного оболочкой; это также позволяет избежать риска переполнения буфера командной строки оболочкой.
if test -n "$(find /dir/to/search -maxdepth 1 -name 'files*' -print -quit)"
then
echo found
else
echo not found
fi
В версиях find, отличных от GNU, может не быть параметра -maxdepth, используемого здесь, чтобы find выполнял поиск только по / dir / to / поиск, а не все дерево каталогов, укоренившееся там.
find
обрабатывать подстановочный знак, потому что bash
, расширяя шаблон, пытается отсортировать список совпадающих имен файлов, что расточительно и может быть дорогостоящим.
- person musiphil; 22.06.2012
find
, еще более расточителен, если в каталоге всего несколько файлов (или ни одного).
- person dolmen; 24.02.2017
bash
с подстановочными знаками может занять больше времени, чем запуск find
.
- person musiphil; 13.03.2017
find
, вероятно, тоже не удастся. Также обратите внимание, что перечисление всех файлов с помощью find только для того, чтобы затем проверить, является ли этот вывод пустым или нет, является большой тратой ресурсов.
- person dolmen; 13.04.2017
find: '/dir/to/search': No such file or directory
; Вы можете подавить это с помощью -quit 1> /dev/null 2>&1
- person rubo77; 23.04.2017
find
с -quit
, как описано в сообщении @flabdablet, не повлияет на огромное количество файлов, потому что он завершает работу, как только находит первое совпадение, и, следовательно, не выводит список всех файлов. Так что это не такая большая трата ресурсов, как вы предлагаете. Более того, find
не просто расширяет подстановочный знак, как это делает оболочка, но проверяет каждый найденный файл на соответствие шаблону, чтобы убедиться в том, что он не дает сбоев для огромного количества файлов.
- person musiphil; 25.04.2017
Вот мой ответ -
files=(xorg-x11-fonts*)
if [ -e "${files[0]}" ];
then
printf "BLAH"
fi
unsetopt nomatch
, если zsh сообщает об ошибках.
- person Chih-Hsuan Yen; 03.01.2015
shopt -s nullglob
для bash
- person nhed; 28.06.2016
sh
.
- person tripleee; 26.09.2017
xorg-x11-fonts*
. В противном случае -e
позаботится о проверке (нерасширенный xorg-x11-fonts*
не пройдёт проверку).
- person kkm; 15.02.2020
${files[0]-}
, что в точности совпадает с ${files-}
. В противном случае, если звездочки выровнены неудачно так, что действуют как set -u
, так и shopt -s nullglob
, расширение не удастся.
- person kkm; 15.02.2020
Вы можете сделать следующее:
set -- xorg-x11-fonts*
if [ -f "$1" ]; then
printf "BLAH"
fi
Это работает с sh и производными: ksh и bash. Он не создает суб-оболочки. Команды $ (..) и `...`, используемые в других решениях, создают вспомогательную оболочку: они разветвляют процесс и неэффективны. Конечно, он работает с несколькими файлами, и это решение может быть самым быстрым или вторым после самого быстрого.
Это тоже работает, когда нет совпадений. Как сказал один из комментаторов, нет необходимости использовать nullglob. $ 1 будет содержать исходное имя теста, поэтому test -f $ 1 не будет успешным, потому что файл $ 1 не существует.
for i in xorg-x11-fonts*; do
if [ -f "$i" ]; then printf "BLAH"; fi
done
Это будет работать с несколькими файлами и с пробелами в именах файлов.
break
для выхода из цикла после первого совпадения.
- person tripleee; 27.05.2016
existsAnyFile () { for file; do [ -f "$file" ] && return 0; done; false; }
- person sdenham; 30.06.2016
ОБНОВЛЕНИЕ:
Хорошо, теперь у меня определенно есть решение:
files=$(ls xorg-x11-fonts* 2> /dev/null | wc -l)
if [ "$files" != "0" ]
then
echo "Exists"
else
echo "None found."
fi
> Exists
ls
может работать довольно медленно в каталоге с большим количеством файлов (вероятно, из-за сортировки). По крайней мере, вы можете отключить сортировку с помощью -U
.
- person musiphil; 22.06.2012
ls
и wc
требуется запустить две внешние программы. Совершенно неэффективно.
- person dolmen; 24.02.2017
Может быть, это кому-то поможет:
if [ "`echo xorg-x11-fonts*`" != "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
xorg-x11-fonts\*
существует?
- person mlathe; 12.10.2016
Вопрос не был специфическим для Linux / Bash, поэтому я подумал, что добавлю способ Powershell, который обрабатывает подстановочные знаки по-разному - вы помещаете его в кавычки, как показано ниже:
If (Test-Path "./output/test-pdf-docx/Text-Book-Part-I*"){
Remove-Item -force -v -path ./output/test-pdf-docx/*.pdf
Remove-Item -force -v -path ./output/test-pdf-docx/*.docx
}
Я думаю, что это полезно, потому что концепция исходного вопроса охватывает «оболочки» в целом, а не только Bash или Linux, и применима также к пользователям Powershell с тем же вопросом.
pwsh
- вещь.
- person Chaim Eliyah; 17.01.2020
Строго говоря, если вы хотите напечатать только «Blah», вот решение:
find . -maxdepth 1 -name 'xorg-x11-fonts*' -printf 'BLAH' -quit
Вот еще один способ:
doesFirstFileExist(){
test -e "$1"
}
if doesFirstFileExist xorg-x11-fonts*
then printf "BLAH"
fi
Но я думаю, что наиболее оптимальным является следующее, потому что он не пытается сортировать имена файлов:
if [ -z `find . -maxdepth 1 -name 'xorg-x11-fonts*' -printf 1 -quit` ]
then printf "BLAH"
fi
-exec
вариант поиска, например: find . -maxdepth 1 -name '*.o' -exec rm {} \;
- person user3405291; 14.03.2018
Вот решение вашей конкретной проблемы, которое не требует for
циклов или внешних команд, таких как ls
, find
и т.п.
if [ "$(echo xorg-x11-fonts*)" != "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
Как видите, это немного сложнее, чем вы надеялись, и полагается на тот факт, что, если оболочка не может расширить глобус, это означает, что файлы с этим глобусом не существуют, и echo
выведет glob < em> как есть, что позволяет нам проводить простое сравнение строк, чтобы проверить, существует ли вообще какой-либо из этих файлов.
Однако, если мы будем обобщать процедуру, мы должны принять во внимание тот факт, что файлы могут содержать пробелы в своих именах и / или путях и что glob char может по праву расширяться до нуля (в вашем примере это будет случай файла с именем в точности xorg-x11-fonts).
Этого можно добиться с помощью следующей функции в bash.
function doesAnyFileExist {
local arg="$*"
local files=($arg)
[ ${#files[@]} -gt 1 ] || [ ${#files[@]} -eq 1 ] && [ -e "${files[0]}" ]
}
Возвращаясь к вашему примеру, его можно было бы вызвать так.
if doesAnyFileExist "xorg-x11-fonts*"; then
printf "BLAH"
fi
Расширение глобуса должно происходить внутри самой функции, чтобы она работала должным образом, поэтому я заключил аргумент в кавычки, и именно для этого предназначена первая строка в теле функции: так что любые несколько аргументов (которые могут быть результатом глобуса расширение вне функции, а также ложный параметр) будут объединены в один. Другой подход может заключаться в выдаче ошибки при наличии более одного аргумента, а другой может заключаться в игнорировании всех аргументов, кроме 1-го.
Вторая строка в теле функции устанавливает files
var в массив, состоящий из всех имен файлов, до которых расширяется глобус, по одному для каждого элемента массива. Это нормально, если имена файлов содержат пробелы, каждый элемент массива будет содержать имена как есть, включая пробелы.
Третья строка в теле функции выполняет две функции:
Сначала он проверяет, есть ли в массиве более одного элемента. Если это так, это означает, что глобус наверняка был расширен до чего-то (из-за того, что мы сделали в первой строке), что, в свою очередь, означает, что существует хотя бы один файл, соответствующий глобу, а это все, что мы хотели. знать.
Если на шаге 1. мы обнаружили, что у нас меньше двух элементов в массиве, то мы проверяем, есть ли один, и если да, то проверяем, существует ли он, обычным способом. Нам нужно выполнить эту дополнительную проверку, чтобы учесть аргументы функции без глобальных символов, и в этом случае массив содержит только один, нерасширенный элемент.
$(..)
запускает вспомогательную оболочку.
- person dolmen; 24.02.2017
ls
, которая для всех целей и задач столь же эффективна (или неэффективна), как и вспомогательная оболочка.
- person Fabio A.; 28.03.2017
Код на bash, который я использую
if ls /syslog/*.log > /dev/null 2>&1; then
echo "Log files are present in /syslog/;
fi
Спасибо!
Нашел пару интересных решений, которыми стоит поделиться. Первый по-прежнему страдает от проблемы «это сломается, если будет слишком много совпадений»:
pat="yourpattern*" matches=($pat) ; [[ "$matches" != "$pat" ]] && echo "found"
(Напомним, что если вы используете массив без синтаксиса [ ]
, вы получаете первый элемент массива.)
Если в вашем скрипте есть «shopt -s nullglob», вы можете просто сделать:
matches=(yourpattern*) ; [[ "$matches" ]] && echo "found"
Теперь, если в каталоге может быть тонна файлов, вы в значительной степени застряли в использовании find:
find /path/to/dir -maxdepth 1 -type f -name 'yourpattern*' | grep -q '.' && echo 'found'
Использование новых причудливых функций shmancy в оболочках ksh, bash и zsh (в этом примере не обрабатываются пробелы в именах файлов):
# Declare a regular array (-A will declare an associative array. Kewl!)
declare -a myarray=( /mydir/tmp*.txt )
array_length=${#myarray[@]}
# Not found if the 1st element of the array is the unexpanded string
# (ie, if it contains a "*")
if [[ ${myarray[0]} =~ [*] ]] ; then
echo "No files not found"
elif [ $array_length -eq 1 ] ; then
echo "File was found"
else
echo "Files were found"
fi
for myfile in ${myarray[@]}
do
echo "$myfile"
done
Да, это действительно пахнет Perl. Рад, что не вмешался;)
Я использую это:
filescount=`ls xorg-x11-fonts* | awk 'END { print NR }'`
if [ $filescount -gt 0 ]; then
blah
fi
wc -l
более эффективен, чем awk
для этой задачи.
- person dolmen; 24.02.2017
ls
успех или нет (а еще лучше избегать ls
и использовать встроенные функции оболочки).
- person tripleee; 26.09.2017
ИМХО лучше использовать find
всегда при тестировании файлов, глобусов или каталогов. Камнем преткновения при этом является статус выхода find
: 0, если все пути были пройдены успешно,> 0 в противном случае. Выражение, которое вы передали find
, не создает эха в его коде выхода.
В следующем примере проверяется, есть ли в каталоге записи:
$ mkdir A
$ touch A/b
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . && echo 'not empty'
not empty
Когда A
не имеет файлов, grep
завершается ошибкой:
$ rm A/b
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . || echo 'empty'
empty
Когда A
не существует, grep
снова выдает ошибку, потому что find
печатает только в stderr:
$ rmdir A
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . && echo 'not empty' || echo 'empty'
find: 'A': No such file or directory
empty
Замените -not -empty
любым другим find
выражением, но будьте осторожны, если -exec
команда выводит на стандартный вывод. В таких случаях вы можете найти более конкретное выражение с помощью grep.
Этот подход хорошо работает в сценариях оболочки. Изначально вопрос заключался в поиске шара xorg-x11-fonts*
:
if find -maxdepth 0 -name 'xorg-x11-fonts*' -print | head -n1 | grep -q .
then
: the glob matched
else
: ...not
fi
Обратите внимание, что ветвление else достигается, если xorg-x11-fonts*
не совпало или find
обнаружила ошибку. Чтобы отличить регистр, используйте $?
.
Попробуй это
fileTarget="xorg-x11-fonts*"
filesFound=$(ls $fileTarget) # 2014-04-03 edit 2: removed dbl-qts around $(...)
редактировать 2014-04-03 (удалены двойные кавычки и добавлен тестовый файл Charlie 22.html (2 пробела)
case ${filesFound} in
"" ) printf "NO files found for target=${fileTarget}\n" ;;
* ) printf "FileTarget Files found=${filesFound}\n" ;;
esac
Тест
fileTarget="*.html" # where I have some html docs in the current dir
FileTarget Files found=Baby21.html
baby22.html
charlie 22.html
charlie21.html
charlie22.html
charlie23.html
fileTarget="xorg-x11-fonts*"
NO files found for target=xorg-x11-fonts*
Обратите внимание, что это работает только в текущем каталоге или где var fileTarget
включает путь, который вы хотите проверить.
fileTarget
содержит пробелы (например, fileTarget="my file*"
).
- person Richard Hansen; 17.06.2011
if ls "my file"* >/dev/null 2>&1; then ...
- person Richard Hansen; 29.03.2014
case "${filesFound}" in ....
. Всем удачи.
- person shellter; 02.04.2014
case
, слово после case
не подлежит разделению полей или расширению имени пути, поэтому добавленные вами двойные кавычки не действуют. Проблема с разделением полей в ls $fileTarget
.
- person Richard Hansen; 03.04.2014
charlie 22.html
, я отредактировал результаты выше. Будет ли это обрабатывать каждый случай так же хорошо, как find ... -print0 | xargs -0 ..
?, Возможно, нет. Работает ли он в среде, где вы контролируете, какие имена файлов создаются? Для меня это работает, и я имею в виду, что я использую эту конструкцию регулярно (в среде, где я контролирую создаваемые имена файлов ;-)). Всем удачи.
- person shellter; 03.04.2014
Как насчет
if ls -l | grep -q 'xorg-x11-fonts.*' # grep needs a regex, not a shell glob
then
# do something
else
# do something else
fi
ls
в сценариях, а подстановочный знак .*
является избыточным (вы, вероятно, имели в виду grep -q '^xorg-x1-fonts'
).
- person tripleee; 26.09.2017
ls
- person phuclv; 31.05.2018
Если в сетевой папке огромное количество файлов, использование подстановочного знака вызывает сомнения (скорость или переполнение аргументов командной строки).
В итоге я получил:
if [ -n "$(find somedir/that_may_not_exist_yet -maxdepth 1 -name \*.ext -print -quit)" ] ; then
echo Such file exists
fi
Вы также можете вырезать другие файлы
if [ -e $( echo $1 | cut -d" " -f1 ) ] ; then
...
fi
мужской тест
if [ -e file ]; then
...
fi
будет работать для dir \ file.
С уважением
bash: [: too many arguments
- person user000001; 17.04.2013
ls
в скриптах, не проверяйте, равно ли нулю количество слов, следите за логикой кренделя с обратными кавычками.
- person tripleee; 31.07.2020
[
будет передано несколько аргументов, скорее всего, вызов[
завершится с ошибкой и, следовательно, будет интерпретирован как отсутствие соответствия файлов. - person Richard Hansen   schedule 17.06.2011