Warum sind beim Aufrufen dieses Bash-Skripts Anführungszeichen für das Argument files erforderlich?

13

Ich bin ziemlich neu in Bash-Scripting. Ich habe ein "Testskript", das ich als Grundlage für ein erweitertes / nützliches Skript verwendet habe:

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

Wenn ich dies ohne Anführungszeichen aufrufe, nimmt es nur eine Datei in einem Verzeichnis auf:

testscript *.txt

Aber wenn ich es mit Anführungszeichen aufrufe, funktioniert es korrekt und wählt alle Textdateien aus:

testscript '*.txt'

Was geht hier vor sich?

gornvix
quelle
Um sehr, sehr klar zu sein, ist der richtige Weg, dies zu beheben, das Ausführen for a in "$@"; do(oder for a; do) in Ihrem Skript, so dass das Globbing der äußeren Shell überlassen wird, und nicht die Anführungszeichen.
Charles Duffy
Das ist einen Blick wert. guide.bash.academy
vascowhite

Antworten:

29

Wenn Sie ein Programm aufrufen

testscript *.txt

Dann führt Ihre Shell die Erweiterung durch und berechnet alle Werte. So könnte es sein, dass Sie Ihr Programm effektiv als aufrufen

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

Jetzt sieht dein Programm nur noch an $1und funktioniert so nur noch weiter file1.txt.

Indem Sie in der Befehlszeile Anführungszeichen setzen, übergeben Sie die Literalzeichenfolge *.txtan das Skript, und das ist, was in gespeichert ist $1. Ihre forSchleife erweitert es dann.

Normalerweise würden Sie "$@"und nicht $1in solchen Skripten verwenden.

Dies ist ein "gotcha" für Benutzer, die mit CMD-Skripten arbeiten, bei denen die Befehlsshell kein Globbing ausführt (wie es bekannt ist) und immer die Literalzeichenfolge übergibt.

Stephen Harris
quelle
6
Nur um zu klären (für andere Personen als den Autor der oben Antwort) unter Verwendung von "$@"(im Gegensatz zu $@oder $1 $2 $3) wird jeder Dateinamen verursachen zitiert werden "file1.txt" "file2.txt"usw. Für file1.txtdiese sinnlos ist, aber wenn Sie haben my file.txt, ist die zitierte kritische um die Schale zu verhindern Parsing, um es in zwei Dateinamen zu verwandeln, einen mit dem Namen myund einen mit dem Namen file.txt. Geben Sie immer Benutzereingaben und globale Erweiterungen an, damit Sie eines Tages nicht sehr unglücklich sind.
Seth Robertson
2
Und dies ist nicht nur theoretisch - Mac OS X wurde einmal mit einem Update-Skript ausgeliefert, das die Argumente nicht richtig zitierte und unter bestimmten Umständen die Festplatten der Benutzer löschte.
flauschige
2
@fluffy, hast du einen Link dazu?
Wildcard
@Wildcard Leider kann ich keine Artikel darüber finden, aber es war eine große Neuigkeit in der Technologiewelt, als es passierte. Ich möchte sagen, dass es 2003/2004 oder so war, als Apple noch den Dreh raus bekam, ein UNIX-Distributor zu sein.
flauschige
1
@wildcard Ah, habe es gefunden! xlr8yourmac.com/OSX/itunes2_erased_drives.html - es war tatsächlich ein iTunes-Upgrade-Skript, das der Schuldige war.
flauschige
7

Ohne Anführungszeichen wird die Shell *.txtvor dem Aufrufen des Skripts erweitert, sodass $1nur die erste Datei erweitert wird. Alle txtDateien sind zu diesem Zeitpunkt Argumente für Ihr Skript (sofern nicht zu viele vorhanden sind).

Bei Anführungszeichen wird diese Zeichenfolge übergeben, ohne dass sie in das Skript eingebunden wird. forDadurch kann die Erweiterung erfolgen, wie Sie es sich erhofft haben.

Eric Renouf
quelle