Es ist deine Entscheidung. Wenn Sie $@
keinen seiner Werte angeben, werden diese zusätzlich erweitert und interpretiert. Wenn Sie es zitieren, werden alle übergebenen Argumente der Funktion in ihrer Erweiterung wörtlich wiedergegeben. Sie werden niemals in der Lage sein, zuverlässig mit Shell-Syntax-Token wie &>|
und usw. umzugehen, ohne die Argumente selbst zu analysieren - und so bleibt Ihnen die vernünftigere Wahl, Ihre Funktion einer der folgenden Möglichkeiten zu übergeben:
- Genau die Wörter, die bei der Ausführung eines einzelnen einfachen Befehls mit verwendet werden
"$@"
.
...oder...
- Eine weiter erweiterte und interpretierte Version Ihrer Argumente, die erst dann zusammen als einfacher Befehl mit übernommen werden
$@
.
Keiner der Wege ist falsch, wenn er absichtlich ist und die Auswirkungen Ihrer Wahl gut verstanden werden. Beide Möglichkeiten haben Vorteile gegenüber den anderen, obwohl die Vorteile der zweiten selten besonders nützlich sein dürften. Immer noch...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... es ist nicht nutzlos , nur selten von großem Nutzen . Und in einer bash
Schale, weil die bash
Voreinstellung nicht hält eine Variablendefinition an seine Umgebung , auch wenn die Definition der Befehlszeile eines speziellen builtin oder zu einer Funktion vorangestellt wird, für den globalen Wert $IFS
ist nicht betroffen, und ihre Erklärung ist lokal nur zum run_this()
anruf.
Ähnlich:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... das Globbing ist auch konfigurierbar. Zitate dienen einem Zweck - sie sind nicht umsonst. Ohne sie wird die Shell-Erweiterung einer zusätzlichen Interpretation unterzogen - konfigurierbare Interpretation. Früher war es - mit einigen sehr alten Shells - das, $IFS
was global auf alle Eingaben angewendet wurde , und nicht nur auf Erweiterungen. Tatsächlich verhielten sich die Shells sehr ähnlich dahingehend, run_this()
dass sie alle Eingabewörter auf den Wert von brachen $IFS
. Wenn Sie also nach diesem sehr alten Shell-Verhalten suchen, sollten Sie es verwenden run_this()
.
Ich suche nicht danach und bin im Moment ziemlich gedrängt, ein nützliches Beispiel dafür zu finden. Ich bevorzuge im Allgemeinen, dass die Befehle, die meine Shell ausführt, die sind, die ich tippe. Und wenn ich die Wahl hätte, würde ich es fast immer tun run_that()
. Außer dass...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
Fast alles kann zitiert werden. Befehle werden in Anführungszeichen ausgeführt. Dies funktioniert, da zum Zeitpunkt der tatsächlichen Ausführung des Befehls alle Eingabewörter bereits in Anführungszeichen gesetzt wurden - dies ist die letzte Stufe des Eingabe-Interpretationsprozesses der Shell. So ist der Unterschied zwischen 'ls'
und ls
kann nur Materie , während die Shell interpretiert - und deshalb zitiert wird ls
sichergestellt , dass Alias Name ls
nicht für mein zitierte ersetzt wird ls
Befehlswort. Ansonsten wirken sich die Anführungszeichen nur auf die Abgrenzung von Wörtern aus (das ist, wie und warum das Zitieren von Variablen / Eingabe-Leerzeichen funktioniert) sowie auf die Interpretation von Metazeichen und reservierten Wörtern.
So:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Sie werden das niemals mit run_this()
oder tun können run_that()
.
Aber Funktionsnamen, $PATH
'd-Befehle oder integrierte Befehle werden in Anführungszeichen oder ohne Anführungszeichen ausgeführt, und genau so run_this()
und überhaupt nicht run_that()
. Sie werden mit all diesen Dingen nichts Nützliches $<>|&(){}
anfangen können. Kurz eval
ist.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Andernfalls sind Sie aufgrund der von Ihnen verwendeten Anführungszeichen an die Grenzen eines einfachen Befehls gebunden (auch wenn dies nicht der $@
Fall ist, da der Befehl wie ein Anführungszeichen zu Beginn des Prozesses behandelt wird, wenn er nach Metazeichen analysiert wird) . Dieselbe Einschränkung gilt für Befehlszeilenzuweisungen und -umleitungen, die auf die Befehlszeile der Funktion beschränkt sind. Aber das ist keine große Sache:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
Ich hätte dort genauso leicht <
Ein- oder >
Ausgänge umleiten können, wie ich die Pipe geöffnet habe.
Auf jeden Fall gibt es hier keinen richtigen oder falschen Weg - jeder Weg hat seinen Nutzen. Sie sollten es nur so schreiben, wie Sie es verwenden möchten, und Sie sollten wissen, was Sie vorhaben. Das Weglassen von Zitaten kann einen Zweck haben - sonst gäbe es keinen sein , überhaupt zitiert - aber wenn man sie weglassen Gründen nicht relevant für Ihre Zwecke, sind Sie nur schlechten Code zu schreiben. Tu was du meinst; Ich versuche es trotzdem.
run_that
Das Verhalten von ist definitiv das, was ich erwarten würde (was ist, wenn der Pfad zum Befehl ein Leerzeichen enthält?). Wenn Sie das andere Verhalten wollte, sicherlich würden Sie es am Ende des Zitats Anruf -Ort , wo Sie wissen , was die Daten? Ich würde erwarten, diese Funktion als zu bezeichnenrun_that ls -l
, die in beiden Versionen gleich funktioniert . Gibt es einen Fall, den Sie anders erwarten ließen?