Vorrang für Pipes & Redirection-Bindungen mit Disjunkten, Konjunkten usw.?

8

Ich kenne die relative verbindliche Priorität der Operatoren ';', '&', '&&' oder '||'

http://www.gnu.org/software/bash/manual/bashref.html#Lists

Aber wenn Pfeifen zusammen mit '&&' ins Bild kommen, habe ich Schwierigkeiten, die Bindungsstärke zu verstehen und stolpere entweder über einen korrekten Befehl oder gebe einfach auf.

Was ist der verbindliche Vorrang von '|' und '>' im Vergleich zu oben?

Beispiel, wo ich verwirrt bin:

ls _thumbnails/video.mp4.jpg 2>/dev/null 
    && echo "thumbnail already generated. Not regenerating" \
    && exit \
    || ffmpeg_thumbnail_create video.mp4 2>/dev/null \
    && ls _thumbnails/video.mp4.jpg \
    && echo "Thumbnail successfully created" \
    && exit \
    || echo "Thumbnail creation failed" \
    | tee ~/thumbnails.log

Das Ziel des oben genannten ist es, genau dann ein Miniaturbild zu erstellen, wenn noch keines vorhanden ist (ich führe täglich einen Cronjob durch). Und ich mag die enorme Menge an Ausgabe von ffmpeg nicht, wenn kein Fehler vorliegt (was nicht der Unix-Weg ist). Es gibt auch andere Situationen. Geben Sie mir also keine Ratschläge, die separate Anweisungen oder spezielle Optionen für diese Programme verwenden. Ich möchte den verbindlichen Vorrang verstehen.

Sridhar Sarnobat
quelle
Sehr hilfreich - ich würde dies als richtig markieren, wenn es eine Antwort wäre. Nur noch eine Frage: Wie ändere ich die Priorität? Theoretisch denke ich {... }sollte funktionieren. Ich habe es möglicherweise unsystematisch versucht und nicht die erwarteten Ergebnisse erzielt.
Sridhar Sarnobat

Antworten:

12

Die kurze Antwort lautet : <, >und ihre Varianten haben die höchste Bindungspriorität (engste Bindung), gefolgt von |, gefolgt von &&und ||, gefolgt von ;und &. Also wird nur das echo "Thumbnail creation failed"in die geleitet tee.

Eine etwas längere Antwort würde darauf hinweisen, dass die höchste Priorität tatsächlich die Gruppierung ist, die mit Klammern oder Klammern angegeben werden kann. Zum Beispiel,

A  &&  (B; C)

und

A  &&  { B; C;}

sind ungefähr gleichbedeutend mit

if A
then
    B
    C
fi

Anmerkungen:

  • Die Klammern geben Ihnen eine Unterschale; dh Befehle Bund Cin einem untergeordneten Prozess ausführen . Befehle wie Variablenzuweisungen oder cd haben daher keine Auswirkung auf die übergeordnete Shell. Befehle in geschweiften Klammern werden im selben Prozess wie der ABefehl ausgeführt. Daher ist das Klammerkonstrukt A && { B; C;}näher am if- then- elseKonstrukt.
  • In der Klammer-Syntax muss vor dem {und ein ;(oder ein &oder eine neue Zeile) vor dem ein Leerzeichen stehen }.

Weitere Informationen finden Sie unter Was sind die Steuerungs- und Umleitungsoperatoren der Shell? und wann ist 'wenn' nicht notwendig? (besonders meine Antworten).

Für noch weitere Lektüre finden Sie die bash (1) man - Seite und die POSIX - Spezifikation / Definition der Shell Command Language , insbesondere Abschnitt 2.9, Shell - Befehle und Abschnitt 2.10.2, Shell Grammatikregeln . Dies ist ein Versuch, einen Kontext für das oben Gesagte bereitzustellen:

  • Dinge wie

    • myVar=42
    • IFS= read a
    • date
    • cd /some/directory
    • ls -laR dir1 dir2
    • cat foo* > /tmp/allfoo
    • ls -laR dir{1,2}
    • find . -type f -name "foo*" -print > /tmp/output 2> /dev/null
    • > newfile
    • [ -f catfood ]
    • exit

    werden alle als "einfache Befehle" betrachtet.

  • Dinge wie
      simple_command 1   |   simple_command 2   |   simple_command 3
    sind "Pipelines". Die Grammatik legt Bausteine ​​fest und baut darauf auf, wie es für formale Grammatiken wie diese (und für Programmiersprachen wie C) typisch ist. Daher wird ein einzelner „einfacher Befehl“ als „Pipeline“ betrachtet, obwohl er keine enthält ein Rohr. Es ist nicht (semantisch) sinnvoll, dass eine Variablenzuweisung Bestandteil einer Pipeline ist, aber Dinge wie x=1 | od -aboder ls -laR | z=0sind syntaktisch gültig.
  • Dinge wie
      Pipeline 1   &&   Pipeline 2   ||   Pipeline 3
      werden von bash als "Listen" und von POSIX als "UND-ODER-Listen" bezeichnet. Auch hier wird eine einzelne "Pipeline" oder sogar ein einzelner "einfacher Befehl" als "UND-ODER-Liste" betrachtet, obwohl sie kein UND oder ODER enthält.
    • Wenn Sie zu Dingen wie kommen
        UND-ODER-Liste 1  &   UND-ODER-Liste 2  ;   UND-ODER-Liste 3
        Die Nomenklatur wird etwas inkonsistent. Bash nennt diese "Listen" auch; POSIX nennt sie "Listen", "zusammengesetzte Listen" und (selten) "Begriffe". Auch hier wird eine einzelne "UND-ODER-Liste", "Pipeline" oder sogar ein einzelner "einfacher Befehl" als "Liste" betrachtet, obwohl sie kein &oder ein enthält ;.
      • Dinge wie
          ( zusammengesetzte_Liste )
          und
            {  zusammengesetzte_Liste ;}
            und die Strömungssteuerbefehle ( for,  if- then- else,  while, etc.) werden als „Verbindung - Befehle“ bezeichnet. 
          • In den obigen Beispielen, ist es wahrscheinlich der am meisten Sinn zu interpretieren A, Bund CPipelines zu sein. Denken Sie daran, dass eine „Pipeline“ ein einzelner „einfacher Befehl“ sein kann. Es muss kein Rohr enthalten.

            G-Man sagt "Reinstate Monica"
            quelle
            1
            Danke für die ausführliche Erklärung über die Rolle der (.. )und {.. }. Ich war aus früheren schlechten Erfahrungen zu dem Schluss gekommen, dass runde Klammern nur im Zusammenhang mit "dynamischen Befehlen" (dh $(.. )) verwendet wurden, da ich sie kaum dazu bringen konnte, etwas in Bezug auf Assoziativität zu tun.
            Sridhar Sarnobat