[ -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.