[ -f /*.txt ]
вернет true, только если есть один (и только один) не скрытый файл, в /
имени которого заканчивается имя, .txt
и если этот файл является обычным файлом или символической ссылкой на обычный файл.
Это связано с тем, что подстановочные знаки раскрываются оболочкой перед передачей в команду (здесь [
).
Так что, если есть /a.txt
и /b.txt
, [
будут переданы 5 аргументов: [
, -f
, /a.txt
, /b.txt
и ]
. [
потом жаловался бы, что -f
дано слишком много аргументов.
Если вы хотите убедиться, что *.txt
шаблон расширяется хотя бы до одного скрытого файла (обычного или нет):
shopt -s nullglob
set -- *.txt
if [ "$#" -gt 0 ]; then
./script "$@" # call script with that list of files.
fi
# Or with bash arrays so you can keep the arguments:
files=( *.txt )
# apply C-style boolean on member count
(( ${#files[@]} )) && ./script "${files[@]}"
shopt -s nullglob
является bash
конкретным, но скорлупа нравится ksh93
, zsh
, yash
, tcsh
имеют эквивалентные высказывания.
Обратите внимание, что он находит эти файлы, читая содержимое каталога, он вообще не пытается получить доступ к этим файлам, что делает его более эффективным, чем решения, которые вызывают такие команды, как ls
или stat
в этом списке файлов, вычисляемых оболочкой.
Стандартный sh
эквивалент будет:
set -- [*].txt *.txt
case "$1$2" in
('[*].txt*.txt') ;;
(*) shift; script "$@"
esac
Проблема в том, что с оболочками Bourne или POSIX, если шаблон не совпадает, он расширяется до самого себя. Так что, если *.txt
расширится до *.txt
, вы не знаете, будет ли это потому, что в .txt
каталоге нет файла или потому что есть один названный файл *.txt
. Использование [*].txt *.txt
позволяет различать два.
/
? Кроме того, вы пропустите точку с запятой раньшеfi
.