Le scénario classique avec Operator Precedence, vous avez une ligne comme:
(cd ~/screenshots/ && ls screenshot* | head -n 5)
Et vous ne savez pas si c'est analysé ((A && B) | C)
ou (A && B | C)
...
La documentation presque officielle trouvée ici ne répertorie pas le canal dans la liste, je ne peux donc pas simplement vérifier dans le tableau.
De plus, en bash, ce (
n'est pas seulement pour changer l'ordre des opérations mais cela crée un sous-shell , donc je ne suis pas sûr à 100% que cette ligne est l'équivalent de la ligne précédente:
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
Plus généralement, comment connaître l' AST d'une ligne bash? En python, j'ai une fonction qui me donne l'arbre afin que je puisse facilement vérifier l'ordre des opérations.
|
s'agit que d'un connecteur qui adapte la sortie standard LHS à la sortie standard RHS. Donc, si lacd
commande de votre exemple échoue, elle n'enverra aucune sortie àhead
, maishead
en faitexecute
, analysera le rien et ne retournera aucune sortie.bash
utilise un analyseur yacc pas quelque chose d'ad-hoc; si vous exécutez cela,yacc -v
cela vous donneray.output
une belle grammaire qui montre cela&&
et||
combine des listes, et les listes sont finalement constituées de pipelines (et non l'inverse); tl; dr;A && B | C
est le même queA && { B | C; }
, comme prévu. N'assumez aucun ordre d'exécution entreB
etC
; les commandes d'un pipeline sont exécutées en parallèle .[...]
tests et$((...))
les évaluations arithmétiques; en particulier,||
et&&
comme utilisé avec la liste des commandes dans le langage shell ont la même priorité , contrairement aux opérateurs respectifs dansC
ou dans l'évaluation arithmétique (où&&
se lie plus étroitement que||
).Réponses:
Cela équivaut à
(le groupe d'accolades commande ensemble sans sous-coque ). La priorité de
|
est donc plus élevée (se resserre) que&&
et||
. C'est,et
signifie toujours que la sortie ne B doit être donnée à C . Vous pouvez utiliser
(...)
ou{ ... ; }
pour joindre des commandes ensemble en une seule entité pour la désambiguïsation si nécessaire:Vous pouvez tester cela à l'aide de différentes commandes. Si vous courez
alors vous aurez
retour: en
tr a-z A-Z
majuscules son entrée , et vous pouvez voir que seul yecho world
était canalisé, tout en étantecho hello
passé par lui-même.Ceci est défini dans la grammaire du shell , bien que ce ne soit pas très clair: la
and_or
production (pour&&
/||
) est définie pour avoir aapipeline
dans son corps, alors qu'ellepipeline
contient justecommand
, qui ne contient pasand_or
- seule lacomplete_command
production peut atteindreand_or
, et elle n'existe qu'au niveau supérieur et à l'intérieur des corps des constructions structurelles comme les fonctions et les boucles.Vous pouvez appliquer manuellement cette grammaire pour obtenir un arbre d'analyse pour une commande, mais Bash ne fournit rien lui-même. Je ne connais aucun shell qui fasse au-delà de ce qui est utilisé pour leur propre analyse.
La grammaire shell a beaucoup de cas spéciaux définis uniquement de manière semi-formelle et il peut être assez difficile de bien faire les choses. Même Bash lui-même s'est parfois trompé , de sorte que les aspects pratiques et l'idéal peuvent être différents.
Il existe des analyseurs externes qui tentent de faire correspondre la syntaxe et de produire un arbre, et parmi ceux-ci, je recommanderai largement Morbig , qui tente d'être le plus fiable.
la source
TL; DR : liste les séparateurs tels que
;
.&
,&&
et||
décidez de l'ordre d'analyse.Le manuel bash nous dit:
Ou comment le wiki de Bash Hacker a dit succinctement
Ainsi,
cd ~/screenshots/ && ls screenshot* | head -n 5
il y a un pipeline -ls screenshot* | head -n 5
et une commande simplecd ~/screenshots/
. Notez que selon le manuelEn revanche,
(cd ~/screenshots/ && ls screenshot*) | head -n 5
c'est différent - vous avez un pipeline: à gauche il y a un sous-shell et à droite vous en avezhead -n 5
. Dans ce cas, en utilisant la notation OP, il serait(A && B) | C
Prenons un autre exemple:
Ici, nous avons une liste
<pipeline1> && <pipeline2>
. Puisque nous savons que l'état de sortie du pipeline est le même que celui de la dernière commande etfalse
renvoie un état négatif, c'est-à-dire échouer,&&
ne s'exécutera pas à droite.Ici, le pipeline de gauche a un statut de sortie réussi, donc le pipeline de droite est exécuté et nous voyons sa sortie.
Notez que la grammaire du shell n'implique pas l'ordre d'exécution réel. Pour citer une des réponses de Gilles :
Et du manuel bash:
Sur la base de cela,
cd ~/screenshots/ && ls screenshot* | head -n 5
lecd ~/screenshots/
serait exécuté en premier,ls screenshot* | head -n 5
si la commande précédente réussit, maishead -n 5
peut être un premier processus généré plutôt quels
car ils sont dans un pipeline.la source
cd ~/screenshots/ && ls screenshot*
ouhead -n 5
" Eh bien, oui, c'est le cas((cd ~/screenshots/ && ls screenshot*) | head -n 5)
. Mais cela ne dit rien sur le cas ambigucd ~/screenshots/ && ls screenshot* | head -n 5
qui semble être le point de la question (avec ou sans parenthèses environnantes).cd ~/screenshots/ && ls screenshot*
devrait être traité en premier car les&&
listes sont plus élevées dans l'ordre de priorité (sur la base de la réponse de l0b0, au moins). Où pensez-vous que je devrais améliorer la réponse?(cd && ls | head)
et((cd && ls) | head)
, il pourrait être bon d'être explicite sur laquelle vous voulez dire.Voici où il est spécifié dans
bash(1)
:Donc,
&&
sépare les pipelines.la source
Vous pourriez simplement essayer
echo hello && echo world | less
. Vous verrez que la|
priorité est plus élevée (un pipeline de commandes est une commande). Là pour votre 2ème exemple n'est PAS le même. Cependant, parce qu'ilcd
n'a pas de sortie, vous ne verrez aucune différence, de façon éthérée.la source