2010-07-19 8 views
5

In sh verstehen (. Beachten Sie, dass die Fehlermeldung über die Befehlszeile erscheint)Kann nicht Befehl Substitution in Fish Shell

fish: Illegal command name “(echo ls)” 
~% (echo ls) 

~% echo (echo ls) 
ls 
~% eval (echo ls) 
bin/ Desktop/ 

fish: Illegal command name “(echo ls)” 
exec (echo ls) 
    ^
~% exec (echo ls) 

Es scheint, dass nur Kommandosubstitution als Parameter eines Befehls arbeitet, nicht als Befehl selbst? Warum?

Nun, die Hilfe doc sagt

Wenn ein Parameter einen Satz von Klammern enthält, wird der Text durch die Klammer umschlossen wird als eine Liste von Befehlen interpretiert werden.

Aber immer noch, warum?

+0

Da die Fehlermeldung über die Befehlszeile angezeigt wird, und es erscheint dass Sie es dann bearbeitet haben, bevor Sie es erneut senden, es ist verwirrend, da keiner der Befehle, die Sie anzeigen, diesen Fehler erzeugt. Vielleicht sollten Sie nach der Fehlermeldung '(echo ls)' einfügen. –

+0

Entschuldigung, ich vermisse die '()'. Bearbeitet. – weakish

Antwort

4

Wie

Dies, weil Befehl Substitutionen Parameter Erweiterungen gehören und als Befehle sind nicht erlaubt.

Ein ähnliches Beispiel:

in sh:

tmpls=ls 
$tmpls 

Aber in Fisch:

% set cmd ls; $cmd 
fish: Variables may not be used as commands. 
... 

Warum

Kurz gesagt, es ist gut für die Überprüfbarkeit

Diese article erklärt Details:

Da es erlaubt ist, Variablen als Befehle in regulären Shells zu verwenden, ist es unmöglich, die Syntax eines Skripts zuverlässig zu überprüfen. Zum Beispiel kann dieser Code-Bash/zsh-Code abhängig von Ihrem Glück legal sein oder auch nicht. Fühlst du dich glücklich?

if true; then if [ $RANDOM -lt 1024 ]; then END=fi; else END=true; fi; $END 

Sowohl bash und zsh Versuch, wenn der Befehl in den aktuellen Puffer zu bestimmen, ist beendet, wenn der Benutzer die Eingabetaste drückt, sondern wegen Fragen wie diese, werden sie manchmal nicht. Noch schlimmer ist, dieses Stück vollkommen legal Code wird von bash abgelehnt:

FI=fi; foo() { if true; then true; $FI; } 

Fisch vermeidet diese Art von Problem, da Variablen nicht als Befehle erlaubt. Alles, was Sie mit Variablen als Befehle tun können, kann mit dem Befehl eval oder mit Funktionen wesentlich sauberer durchgeführt werden.

Aus demselben Grund sind Befehlssubstitutionen nicht als Befehle zulässig.

. (Anmerkung: Das zitierte Beispiel ist nicht fair, da ‚wenn‘ und ‚fi‘ nicht einfache Befehle sind aber reservierte Worte Siehe unten Kommentare.)

+0

Für eine Diskussion dieses Problems in Bezug auf Bash, siehe [BashFAQ/050] (http://mywiki.wooledge.org/BashFAQ/050). –

+1

der Artikel, den Sie in Ihrem "warum" Abschnitt zitiert, ist einfach falsch (zumindest so weit wie dieser Abschnitt betroffen ist). Ein Befehl wie 'FI = fi; foo() {wenn wahr; dann wahr; $ FI; } 'ist * nicht * gültige Shell-Syntax, daher wird sie von allen POSIX-Shells korrekt als Syntaxfehler gekennzeichnet. Wörter wie 'fi' sind reservierte Wörter, und sie werden vor der Worterweiterung erkannt, die' $ FI' auf 'fi' erweitert. – Gilles

+0

@Gilles Danke. Ich habe meine Antwort bearbeitet. – weakish

0

Es hat mit der Reihenfolge der Erweiterungen zu tun.

Von help expand-command-substitution in fish:

Wenn mehrere Parameter Erweiterungen kombiniert werden Erweiterungen in der folgenden Reihenfolge ausgeführt:

* Command substitutions 
* Variable expansions 
* Bracket expansion 
* Pid expansion 
* Wildcard expansion 

Expansions von rechts nach links durchgeführt werden, verschachtelt Halter Erweiterungen werden von innen und außen durchgeführt.

Von man bash:

Die Reihenfolge der Erweiterungen ist: Verstrebung Expansion tilde Expansion, Parameter, variabel und arithmetische Expansion und Befehl Substitution (done in einem Links-nach-rechts-Mode), word Aufspaltung und Pfadname Expansion.

+0

Ich bin immer noch verwirrend. Es scheint, dass Fisch nicht versucht, die Command-Substitution zu erweitern, und nimmt (echo ls) wörtlich als Befehl. – weakish