Warum funktioniert sort <(ls -l), aber sort <(ls -l) schlägt fehl?

32

Heute lerne ich etwas über FIFO mit diesem Artikel: Einführung in Named Pipes , der erwähnt cat <(ls -l).

Ich habe ein paar Experimente mit gemacht sort < (ls -l), bei denen ein Fehler auftaucht:

-bash: syntax error near unexpected token `('`

Dann habe ich festgestellt, dass ich ein zusätzliches Leerzeichen im Befehl falsch eingefügt habe.

Aber warum führt dieser zusätzliche Befehl zu diesem Fehler? Warum muss sich das Umleitungssymbol in der Nähe des befinden (?

Zen
quelle
Es sollte beachtet werden, dass * nix shells die Dinge auf der Basis von Leerzeichen aufteilt, wodurch die von Alec erwähnten Token entstehen.
Küken

Antworten:

45

Weil das kein ist <, ist es ein <()völlig anderes. Dies wird als Prozessersetzung bezeichnet . Es ist eine Funktion bestimmter Shells, mit der Sie die Ausgabe eines Prozesses als Eingabe für einen anderen Prozess verwenden können.

Die Operatoren >und <leiten die Ausgabe in und die Eingabe aus Dateien um . Der <()Bediener befasst sich mit Befehlen (Prozessen), nicht mit Dateien. Wenn du rennst

sort < (ls)

Sie versuchen, den Befehl lsin einer Subshell auszuführen (was die Klammern bedeuten) und diese Subshell dann als Eingabedatei an zu übergeben sort. Dies wird jedoch nicht akzeptiert und Sie erhalten den Fehler, den Sie gesehen haben.

terdon
quelle
3
Ihre Antwort ist gut, aber then sort is attempting to read the subshell as its input file→ das ist offensichtlich falsch, da Bash die Syntax nicht einmal analysieren wird. Weder wird lsnoch sorttatsächlich ausgeführt.
Sleblanc
1
@sebleblanc fair point, umformuliert die Antwort, danke.
terdon
1
In diesem Fall gibt es keine Unterschale. < (ls)ist hier kein gültiges Token.
Dienstag,
@cuonglm nein, weil bash dies als Syntaxfehler behandelt. Mein Punkt ist, dass in einer Unterschale (ls)laufen lswürde.
Terdon
22

Denn so soll es sein.

<(...)in bashist die Syntax für die Prozessersetzung. Es wurde vom selben Operator in kopiert ksh.

<, (, ), |, &, ;Sind spezielle lexikalische Token in bashdenen verwendet werden , in verschiedenen Kombinationen spezielle Operatoren zu bilden. <, <(, <<, <&... haben jeweils ihre Rolle. <ist für die Umleitung. <file, < filewürde Eingaben aus einer Datei umleiten. <'(file)'würde Eingaben aus einer aufgerufenen Datei umleiten (file), ist aber <(file)ein anderer Operator, der kein Umleitungsoperator ist.

< (file)würde <gefolgt von (file). In diesem Zusammenhang in bash, (file)ist nicht gültig. (...)kann in einigen Kontexten als einzelnes Token gültig sein, z.

(sub shell)
func () {
  ...
}
var=(foo bar)

Aber nicht in

sort < (cmd)

In der fishShell ist es anders. In fish, (...)ist für die Befehlssubstitutions (das Äquivalent von $(...)in bash). Und <ist für die Eingabeumleitung wie in Bourne-ähnlichen Shells.

Also in fish:

sort <(echo file)

wäre das gleiche wie:

sort < (echo file)

Das ist:

sort < file

Aber das ist etwas völlig anderes als bashdie Prozessersetzung.

In der yashShell dient eine andere POSIX-Shell <(...)nicht der Prozessersetzung, sondern der Prozessumleitung

Da drin,

sort <(ls -l)

Kurz für:

sort 0<(ls -l)

ist ein Umleitungsoperator. Es ist mehr oder weniger gleichbedeutend mit:

ls -l | sort

Während Sie sich in befinden bash, <(ls -l)wird der Pfad auf den Pfad einer Pipe erweitert.

ls -l | sort /dev/fd/0

In zsh, (...)ist als Globbing-Operator ( (*.txt|*.png)würde zu txtund pngDateien erweitern) und als Glob-Qualifier (wird *(/)zum Beispiel zu Verzeichnisdateien erweitert ) überladen .

In zsh, in:

sort < (ls -l)

Das (ls -l)würde als Glob Qualifier behandelt. Das lGlob-Qualifikationsmerkmal muss mit der Anzahl der Verknüpfungen übereinstimmen und erwartet eine Zahl danach l(wie in ls -ld ./*(l2)der Liste der Dateien mit 2 Verknüpfungen). Daher zsh: number expectedwird dort eine Fehlermeldung angezeigt.

sort < (w)hätte zsh: no matches found: (w)stattdessen einen Fehler ausgegeben, da er (w)mit den Dateien mit leerem Namen übereinstimmt, die beschreibbar sind.

sort < (w|cat)hätte den Inhalt der wund / oder catDateien im aktuellen Verzeichnis sortiert ...

Stéphane Chazelas
quelle
Warum sort < $(ls -l)gibt diese Fehlermeldung:bash: $(ls -l): ambiguous redirect
Edward Torvalds
@edwardtorvalds, da es $(ls -l)sich um mehr als ein Wort handelt. Verwenden Sie Anführungszeichen, um split + glob ( sort < "$(echo file)") zu verhindern . Beachten Sie, dass das Verhalten bashvon POSIX sh in dieser Bash das split + glob auch dort ausführt, wenn es nicht interaktiv ist (nicht, wenn es so aufgerufen wird sh).
Stéphane Chazelas
Wenn ls -l | sort /dev/fd/0ich mir das ansehe, kann ich sagen, dass die Ausgabe von ls -lin gespeichert ist /dev/fd/0und der sortBefehl sie liest, um die gewünschte Ausgabe zu erhalten. Ich verwende tail -f --retry /dev/fd/0, um diese Datei zu überwachen, aber ich erhalte keine Ausgabe. Warum? Wie kann ich diese Datei lesen?
Edward Torvalds
Bei Fischen können Sie (foo | psub)eine Substitution des Eingabeprozesses erzielen. Es gibt noch keinen Ersatz (ha) für die Substitution von Ausgabeprozessen.
Zanchey,