Priorité de liaison des tuyaux et de la redirection avec les éléments disjoints, conjoints, etc.?

8

Je connais la priorité de liaison relative des opérateurs ';', '&', '&&' ou '||'

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

mais lorsque les tuyaux entrent en scène avec '&&', j'ai du mal à comprendre la force de liaison et je tombe sur une commande correcte ou j'abandonne.

Quelle est la priorité contraignante de '|' et '>' par rapport à ce qui précède?

Exemple où je suis confus:

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

Le but de ce qui précède est de créer une vignette si et seulement si une n'est pas déjà présente (j'exécute un cronjob quotidien). Et je n'aime pas l'énorme quantité de sortie de ffmpeg quand il n'y a pas d'erreur (ce qui n'est pas la manière Unix). Il existe également d'autres situations, alors ne commencez pas à me donner des conseils qui utilisent des instructions distinctes ou des options spéciales spécifiques à ces programmes. Je veux comprendre la priorité contraignante.

Sridhar Sarnobat
la source
Très utile - je marquerais cela correctement s'il s'agissait d'une réponse. Encore une question - comment modifier la priorité? En théorie, je pense {... }devrait fonctionner. J'aurais pu l'essayer de manière non systématique et ne pas avoir obtenu les résultats escomptés.
Sridhar Sarnobat

Réponses:

12

La réponse courte est que <, >et leurs variantes ont la priorité de liaison la plus élevée (liaison la plus stricte), suivie de |, suivie de &&et ||, suivie de ;et &. Ainsi, seul le echo "Thumbnail creation failed"est canalisé dans le tee.

Une réponse légèrement plus longue indiquerait que la priorité la plus élevée est en fait le regroupement, qui peut être indiqué par des parenthèses ou des accolades. Par exemple,

A  &&  (B; C)

et

A  &&  { B; C;}

sont à peu près équivalents à

if A
then
    B
    C
fi

Remarques:

  • Les parenthèses vous donnent un sous-shell; c'est-à-dire, les commandes Bet Cexécuter dans un processus enfant. Par conséquent, des commandes telles que les affectations de variables ou cd n'auront aucun effet sur le shell parent. Les commandes entre accolades s'exécutent dans le même processus que la Acommande. Par conséquent, la construction de renfort A && { B; C;}est plus proche de la if- then- elseconstruction.
  • Dans la syntaxe d'accolade, il doit y avoir un espace après le {et un ;(ou un &, ou une nouvelle ligne) avant le }.

Pour plus d'informations, voir Quels sont les opérateurs de contrôle et de redirection du shell? et quand «si» n'est pas nécessaire? (en particulier mes réponses).

Pour encore plus de lecture, consultez la page de manuel bash (1) et la spécification / définition POSIX du langage de commande Shell , en particulier la section 2.9, Commandes shell et la section 2.10.2, Règles de grammaire du shell . Il s'agit d'une tentative de fournir un contexte pour ce qui précède:

  • Des choses comme

    • 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

    sont tous considérés comme des «commandes simples».

  • Des choses comme
      simple_command 1   |   simple_command 2   |   simple_command 3
    sont des «pipelines». La grammaire établit des blocs de construction et s'appuie sur eux, comme c'est le cas pour les grammaires formelles comme celle-ci (et pour les langages de programmation comme C), donc une «commande simple» individuelle est considérée comme un «pipeline», même si elle ne contient pas un tuyau. Il n'est pas logique (sémantique) qu'une affectation de variable soit un composant d'un pipeline, mais des choses comme x=1 | od -abou ls -laR | z=0sont syntaxiquement valides.
  • Des choses comme
      pipeline 1   &&   pipeline 2   ||   pipeline 3
      sont appelés «listes» par bash et «listes ET-OU» par POSIX. Encore une fois, un «pipeline» individuel ou même une «commande simple» individuelle est considéré comme une «liste ET-OU», même s'il ne contient ni ET ni OU.
    • Quand vous arrivez à des choses comme
        ET-OU liste 1  &   ET-OU liste 2  ;   Liste ET-OU 3
        la nomenclature commence à devenir un peu incohérente. Bash appelle également ces «listes»; POSIX les appelle «listes», «listes composées» et (rarement) «termes». Encore une fois, une «liste AND-OR», un «pipeline» ou même une «commande simple» individuelle est considérée comme une «liste», même si elle ne contient &ni a ni a ;.
      • Des choses comme
          ( liste_composée )
          et
            {  compound_list ;}
            et les commandes de contrôle de flux ( for,  if- then- else,  while, etc.) sont appelés « composés » commandes. 
          • Dans les exemples ci - dessus, il est sans doute le plus de sens à interpréter A, Bet Cd'être pipelines. N'oubliez pas qu'un «pipeline» peut être une «commande simple» individuelle; il n'a pas besoin de contenir de tuyau.

            G-Man dit «Réintègre Monica»
            la source
            1
            Merci pour l'explication détaillée sur le rôle des (.. )et {.. }. J'avais conclu d'une mauvaise expérience précédente que les crochets n'étaient utilisés que dans le contexte des "commandes dynamiques" (c'est $(-à- dire .. )) car je pouvais à peine leur faire faire quoi que ce soit en matière d'associativité.
            Sridhar Sarnobat