Dlaczego podczas wywoływania tego skryptu Bash konieczne są cudzysłowy dla argumentów plików?


13

Jestem całkiem nowy w skryptach Bash. Mam „skrypt testowy”, którego użyłem jako podstawę do bardziej zaawansowanego / przydatnego skryptu:

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

Kiedy wywołuję to bez cudzysłowów, po prostu wyszukuje jeden plik w katalogu:

testscript *.txt

Ale kiedy nazywam to cudzysłowami, działa poprawnie i wybiera wszystkie pliki tekstowe:

testscript '*.txt'

Co tu się dzieje?


Aby być bardzo, bardzo jasnym, właściwym sposobem na rozwiązanie tego problemu jest uruchomienie for a in "$@"; do(lub for a; do) w skrypcie, pozostawiając globbing zewnętrznej powłoce, aby nie pomijać cudzysłowów.
Charles Duffy,


Warto to zobaczyć. guide.bash.academy
vascowhite

Odpowiedzi:


29

Kiedy wywołujesz program

testscript *.txt

wtedy twoja powłoka wykonuje ekspansję i oblicza wszystkie wartości. Może więc skutecznie wywołać twój program jako

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

Teraz twój program tylko patrzy, $1więc działa tylko file1.txt.

Cytując w wierszu poleceń, przekazujesz dosłowny ciąg *.txtdo skryptu i to jest to, co jest przechowywane $1. Twoja forpętla następnie ją rozszerza.

Zwykle używałbyś tego, "$@"a nie $1w takich skryptach.

Jest to „gotcha” dla osób pochodzących ze skryptów CMD, w których powłoka poleceń nie wykonuje globowania (jak wiadomo) i zawsze przekazuje ciąg literału.


6
Aby to wyjaśnić (dla osób innych niż autor powyższej odpowiedzi), użycie "$@"(w przeciwieństwie do $@lub $1 $2 $3) spowoduje, że każda nazwa pliku będzie cytowana "file1.txt" "file2.txt"itp. file1.txtJest to bez znaczenia, ale jeśli tak my file.txt, to cytowanie ma kluczowe znaczenie dla uniknięcia powłoki parsowanie w celu przekształcenia go w dwa nazwy plików, jeden o nazwie myi jeden o nazwie file.txt. Zawsze podawaj dane wejściowe od użytkowników i globalną ekspansję, aby pewnego dnia nie byłeś bardzo nieszczęśliwy.
Seth Robertson

2
I to nie jest tylko teoria - Mac OS X był kiedyś dostarczany ze skryptem aktualizacji, który nie podawał poprawnie argumentów i w niektórych okolicznościach powodował usuwanie dysków twardych ludzi.
puszysty

2
@fluffy, czy masz link na ten temat?
Wildcard

@Wildcard Niestety nie mogę znaleźć żadnych artykułów na ten temat, ale kiedy to się stało, była to ważna wiadomość w świecie technologii. Chcę powiedzieć, że było to w latach 2003/2004 lub później, kiedy Apple wciąż zaczynało być dystrybutorem UNIX.
puszysty

1
@wildcard Ah, znalazłem to! xlr8yourmac.com/OSX/itunes2_erased_drives.html - to był winowajca skrypt aktualizacji iTunes.
puszysty

7

Bez cudzysłowów powłoka rozwija się *.txtprzed wywołaniem skryptu, więc $1tylko pierwszy plik jest rozszerzany. Wszystkie txtpliki są w tym momencie argumentami twojego skryptu (zakładając, że nie ma ich zbyt wiele).

W przypadku cudzysłowów ciąg ten jest przekazywany bez rozwijania do skryptu, co pozwala na forwykonanie rozwinięcia zgodnie z oczekiwaniami.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.