Im klassischen Szenario mit Operator-Rangfolge haben Sie eine Zeile wie:
(cd ~/screenshots/ && ls screenshot* | head -n 5)
Und Sie wissen nicht, ob es analysiert ((A && B) | C)
oder (A && B | C)
...
Die fast offizielle Dokumentation, die hier zu finden ist, listet die Pipe nicht in der Liste auf, so dass ich nicht einfach in der Tabelle nachschauen kann.
Darüber hinaus dient Bash (
nicht nur zum Ändern der Reihenfolge von Vorgängen, sondern erstellt auch eine Subshell. Daher bin ich mir nicht zu 100% sicher, ob diese Zeile der vorherigen Zeile entspricht:
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
Wie kann man allgemein den AST einer Bash-Linie ermitteln? In Python habe ich eine Funktion, die mir den Baum gibt, so dass ich die Reihenfolge der Operationen leicht überprüfen kann.
|
es sich nur um einen Anschluss handelt, der den LHS-Standard an den RHS-Standard anpasst. Also , wenn dercd
Befehl in Ihrem Beispiel fehlschlägt, würde es keinen Ausgang sendenhead
, aberhead
immer noch in der Tat würdeexecute
, analysiert das nichts, und keine Ausgabe zurück.bash
verwendet ein Yacc- Parser keine Ad-hoc-Sache; Wenn Sie das durchgehenyacc -v
, erhalten Siey.output
eine nette Grammatik, die das zeigt&&
und||
Listen kombiniert, und Listen bestehen schließlich aus Pipelines (und nicht umgekehrt); tl; dr;A && B | C
ist das gleiche wieA && { B | C; }
, wie erwartet. Nehmen Sie keine Ausführungsreihenfolge zwischenB
und anC
. Die Befehle in einer Pipeline werden parallel ausgeführt .[...]
Tests und$((...))
arithmetischen Auswertungen verwendet werden. Insbesondere||
und&&
wie bei Befehlslisten in der Shell-Sprache verwendet, haben sie den gleichen Vorrang , im Gegensatz zu den jeweiligen Operatoren inC
oder bei der arithmetischen Auswertung (wo&&
enger gebunden wird als||
).Antworten:
Dies ist äquivalent zu
(Die geschweiften Klammern gruppieren Befehle ohne Unterschale ). Die Priorität von
|
ist somit höher (bindet enger) als&&
und||
. Das ist,und
bedeutet immer, dass nur der Ausgang von B an C gegeben werden soll . Sie können
(...)
oder verwenden{ ... ; }
, um Befehle zur Disambiguierung als eine Einheit zusammenzufügen:Sie können dies mit verschiedenen Befehlen testen. Wenn du läufst
dann wirst du bekommen
back:
tr a-z A-Z
Großbuchstaben seiner Eingabe , und Sie können sehen, dass nurecho world
in es geleitet wurde, während es von selbstecho hello
durchlief.Dies wird in der Shell-Grammatik definiert , obwohl dies nicht besonders klar ist: Die
and_or
Produktion (für&&
/||
) ist so definiert, dass sie aapipeline
in ihrem Körper hat, während siepipeline
nur enthältcommand
, was nicht enthältand_or
- nur diecomplete_command
Produktion kann erreichenand_or
, und sie existiert nur am oberste Ebene und innerhalb der Körper von strukturellen Konstrukten wie Funktionen und Schleifen.Sie können diese Grammatik manuell anwenden, um einen Analysebaum für einen Befehl zu erhalten, aber Bash stellt selbst nichts bereit. Ich kenne keine Shell, die über das hinausgeht, was für das eigene Parsen verwendet wird.
Die Shell-Grammatik hat viele Sonderfälle, die nur semi-formal definiert sind, und es kann eine ziemliche Aufgabe sein, die richtigen zu finden. Sogar Bash selbst hat es manchmal falsch verstanden , so dass die praktischen Aspekte und das Ideal unterschiedlich sein können.
Es gibt externe Parser, die versuchen, die Syntax abzugleichen und einen Baum zu erzeugen, und von diesen werde ich Morbig allgemein empfehlen , der versucht, der zuverlässigste zu sein.
quelle
TL; DR : Listentrennzeichen wie
;
.&
,&&
Und||
die Analyse , um zu entscheiden.Das Bash-Handbuch sagt uns:
Oder wie es das Wiki von Bash Hacker auf den Punkt gebracht hat
Es
cd ~/screenshots/ && ls screenshot* | head -n 5
gibt also eine Pipeline -ls screenshot* | head -n 5
und einen einfachen Befehlcd ~/screenshots/
. Beachten Sie das laut HandbuchAuf der anderen Seite
(cd ~/screenshots/ && ls screenshot*) | head -n 5
ist es anders - Sie haben eine Pipeline: Auf der linken Seite befindet sich eine Unterschale und auf der rechten Seite haben Sie einehead -n 5
. In diesem Fall wäre es die OP-Notation(A && B) | C
Nehmen wir ein anderes Beispiel:
Hier haben wir eine Liste
<pipeline1> && <pipeline2>
. Da wir wissen, dass der Beendigungsstatus der Pipeline derselbe ist wie der des letzten Befehls und denfalse
negativen Status (auch als fehlgeschlagen bezeichnet) zurückgibt,&&
wird er nicht auf der rechten Seite ausgeführt.Hier hat die linke Pipeline den Status "Erfolgreich beendet". Die rechte Pipeline wird ausgeführt und die Ausgabe wird angezeigt.
Beachten Sie, dass die Shell-Grammatik keine tatsächliche Ausführungsreihenfolge impliziert. Um eine Antwort von Gilles zu zitieren :
Und aus dem Bash-Handbuch:
Basierend auf , dass in
cd ~/screenshots/ && ls screenshot* | head -n 5
dercd ~/screenshots/
würde zuerst ausgeführt werden,ls screenshot* | head -n 5
wenn die vorherige Befehl erfolgreich ist , aberhead -n 5
kann ein erster Prozess als gelaicht eher sein ,ls
da sie in einer Pipeline sind.quelle
cd ~/screenshots/ && ls screenshot*
oderhead -n 5
" Nun ja, das ist der Fall bei((cd ~/screenshots/ && ls screenshot*) | head -n 5)
. Aber es sagt nichts über den zweideutigen Fall aus,cd ~/screenshots/ && ls screenshot* | head -n 5
der der Punkt der Frage zu sein scheint (mit oder ohne umgebende Klammer).cd ~/screenshots/ && ls screenshot*
zuerst verarbeitet werden, da&&
Listen in der Rangfolge höher sind (zumindest basierend auf der Antwort von l0b0). Wo sollte ich die Antwort verbessern?(cd && ls | head)
und((cd && ls) | head)
, könnte es gut sein, genau zu sagen, welche Sie meinen.Hier ist angegeben in
bash(1)
:Trennt also
&&
Pipelines.quelle
Du könntest es einfach versuchen
echo hello && echo world | less
. Sie werden sehen, dass dies|
eine höhere Priorität hat (Eine Pipeline von Befehlen ist ein Befehl). Dort ist für dein 2. Beispiel NICHT dasselbe. Da escd
jedoch keine Ausgabe gibt, werden Sie keinen Unterschied feststellen können.quelle