Existe alguma vantagem em especificar './' em um loop for usando um glob?

10

Fiquei com a impressão de que poderia ser mais seguro usar ./*.fastqao pesquisar arquivos que terminam com .fastq. Por exemplo, ./impediria a captura do arquivo .fastq. Isso está obviamente errado, como mostra o exemplo abaixo:

TMP_DIR=$(mktemp --directory)
mkdir -p ${TMP_DIR}
(cd ${TMP_DIR}
 touch {a,b,c,}.fastq
 ls -a
 echo ""

 echo "# match all:"
 for f in *.fastq ; do
     echo "${f}"
 done
 echo ""

 echo "# with ./:"
 for f in ./*.fastq ; do
     echo "${f}"
 done
)
rm -rf ${TMP_DIR}
.
..
a.fastq
b.fastq
c.fastq
.fastq

# match all:
a.fastq
b.fastq
c.fastq

# with ./:
./a.fastq
./b.fastq
./c.fastq

Nem *.fastqnem ./*.fastqcorresponde ao arquivo .fastq. Então, eu me pergunto agora, há algum ponto em usar ./*.fastqaqui, ou ./*em geral?

Frédéric Mahé
fonte
1
O ponto comum ./*é que ele garante que os nomes que começam com -não sejam tratados como opções.
Charles Duffy

Respostas:

15

Esse é um comportamento curinga inicialmente surpreendente, já que a descrição do *caractere curinga diz:

Corresponde a qualquer sequência, incluindo a sequência nula.

... até você perceber que esse período é um pouco especial quando é o primeiro caractere de um nome de arquivo. O texto introdutório 3.5.8 Filename Expansiondiz:

Quando um padrão é usado para a expansão do nome do arquivo, o caractere '.' no início de um nome de arquivo ou imediatamente após uma barra deve ser correspondido explicitamente, a menos que a opção shell dotglob esteja configurada.

O "padrão de uso" de prefixar curingas com ./é útil para Manipular nomes com traço inicial no shell bash , como comentou o steeldriver. Ele não afeta a expansão de curinga / nome do arquivo, mas torna mais seguro / fácil manipular os nomes de arquivos quando você os consulta, se eles começarem com caracteres que esses programas possam interpretar erroneamente como opções. Por exemplo:

# I want a file named `-n`
$ touch -n
touch: invalid option -- 'n'
Try 'touch --help' for more information.
$ touch -- -n
### ok
$ touch ./-n
### ok

... e agora que tenho um arquivo chamado -n, se um loop for feito com um curinga:

for file in *n
do
  echo "$file"
done

... Não recebo saída!

Mas se eu prefixo o curinga com ./,

for file in ./*n
do
  echo "$file"
done
./-n

... Eu vejo o nome do arquivo.

Este é um exemplo simples para fins de demonstração; veja também Por que printf é melhor que eco? por esse motivo e outros. Outros utilitários serão acionados por outras opções, por isso é melhor apresentar os nomes de arquivos para os utilitários da maneira mais segura possível. Se você não prefixar o curinga para "escapar" dos nomes de arquivos, precisará "proteger" seus utilitários de outras maneiras; um comum é sinalizar o final das opções com --, por exemplo:

for file in *n
do
  mv -- "$file" backup/"$file"
done

... que passará com segurança o -nnome do arquivo para mv(como visto em set -x):

mv -- -n backup/-n
Jeff Schaller
fonte