[ -f /*.txt ]
retornaria true somente se houver um (e apenas um) arquivo não oculto em / cujo nome termine em .txt e se esse arquivo for um arquivo regular ou um symlink para um arquivo regular.
Isso porque os curingas são expandidos pelo shell antes de serem passados para o comando (aqui [ ).
Portanto, se houver um /a.txt e /b.txt , [ receberá 5 argumentos: [ , -f , /a.txt , /b.txt e ] . [ , então, reclama que -f recebe muitos argumentos.
Se você quiser verificar se o padrão *.txt se expande para pelo menos um arquivo não oculto (regular ou não):
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 específico, mas shells como ksh93 , zsh , yash , tcsh têm instruções equivalentes.
Observe que ele localiza esses arquivos lendo o conteúdo do diretório, ele não tenta acessar esses arquivos, o que o torna mais eficiente do que as soluções que chamam comandos como ls ou stat nessa lista. arquivos computados pelo shell.
O equivalente padrão sh seria:
set -- [*].txt *.txt
case "$1$2" in
('[*].txt*.txt') ;;
(*) shift; script "$@"
esac
O problema é que, com os shells Bourne ou POSIX, se um padrão não corresponder, ele se expande para si mesmo. Então, se *.txt for expandido para *.txt , você não sabe se é porque não há nenhum arquivo .txt no diretório ou porque há um arquivo chamado *.txt . Usando [*].txt *.txt permite discriminar entre os dois.