Por que as aspas são necessárias para o argumento dos arquivos ao chamar esse script Bash?

13

Eu sou bastante novo no script Bash. Eu tenho um "testingcript", que usei como base para um script mais avançado / útil:

#!/bin/bash
files=$1
for a in $files
do
    echo "$a"
done

Quando eu chamo isso sem aspas, apenas pega um arquivo em um diretório:

testscript *.txt

Mas quando eu o chamo com aspas, ele funciona corretamente e seleciona todos os arquivos de texto:

testscript '*.txt'

O que está acontecendo aqui?

gornvix
fonte
Para ser muito, muito claro, a maneira correta de corrigir isso é executar for a in "$@"; do(ou for a; do) em seu script, deixando o globbing para o shell externo, para não deixar de fora as aspas.
Charles Duffy
Vale a pena dar uma olhada. guide.bash.academy
vascowhite

Respostas:

29

Quando você chama um programa

testscript *.txt

então seu shell faz a expansão e calcula todos os valores. Portanto, pode chamar efetivamente seu programa como

testscript file1.txt file2.txt file3.txt file4.txt

Agora seu programa apenas analisa $1e, portanto, apenas funciona file1.txt.

Ao citar na linha de comando, você está passando a string literal *.txtpara o script, e é isso que está armazenado $1. Seu forloop então o expande.

Normalmente você usaria "$@"e não $1em scripts como este.

Essa é uma "pegadinha" para pessoas provenientes de scripts CMD, em que o shell de comando não faz globbing (como é conhecido) e sempre passa a string literal.

Stephen Harris
fonte
6
Só para esclarecer (para fins que não o autor da resposta acima de pessoas), usando "$@"(ao contrário $@ou $1 $2 $3) fará com que cada nome de arquivo para ser citado "file1.txt" "file2.txt"etc. Por file1.txtisso não tem sentido, mas se você tiver my file.txt, a citação é fundamental para evitar que o shell análise para transformá-lo em dois nomes de arquivos, um nomeado mye outro nomeado file.txt. Sempre cite a entrada do usuário e a expansão global para que você não fique muito satisfeito algum dia.
Seth Robertson
2
E isso não é apenas teórico - o Mac OS X já foi enviado com um script de atualização que não cita corretamente os argumentos e acaba excluindo os discos rígidos das pessoas em algumas circunstâncias.
fofo
2
@ fofo, você tem um link sobre isso?
Curinga
@Wildcard Infelizmente, não consigo encontrar nenhum artigo sobre isso, mas foram grandes notícias no mundo da tecnologia quando isso aconteceu. Quero dizer que foi em 2003/2004 ou mais ou menos, quando a Apple ainda estava pegando o jeito de ser um distribuidor UNIX.
macia
1
@ cartão virtual Ah, encontrei! xlr8yourmac.com/OSX/itunes2_erased_drives.html - era na verdade um script de atualização do iTunes que era o culpado.
macia
7

Sem aspas, o shell se expande *.txtantes de invocar o script, assim $1como apenas o primeiro arquivo que é expandido. Todos os txtarquivos são argumentos para o seu script nesse ponto (supondo que não haja muitos).

Com aspas, essa string é passada sem ser expandida para o script, que permite fora expansão, como você espera.

Eric Renouf
fonte