El escenario clásico con precedencia de operador, tiene una línea como:
(cd ~/screenshots/ && ls screenshot* | head -n 5)
Y no sabes si está analizado ((A && B) | C)o (A && B | C)...
La documentación casi oficial que se encuentra aquí no enumera la tubería en la lista, por lo que no puedo simplemente verificar en la tabla.
Además, en bash, (no es solo para cambiar el orden de las operaciones, sino que crea una subshell , por lo que no estoy 100% seguro de que estas líneas sean el equivalente de la línea anterior:
((cd ~/screenshots/ && ls screenshot*) | head -n 5)
En términos más generales, ¿cómo saber el AST de una línea bash? En python tengo una función que me da el árbol para que pueda verificar fácilmente el orden de operación.

|es solo un conector que se ajusta a la salida estándar LHS a la entrada estándar RHS. Entonces, si elcdcomando en su ejemplo falla, no enviaría ninguna salidahead, peroheadde hecho aúnexecuteanalizaría la nada y no devolvería ninguna salida.bashestá usando un analizador yacc no algo ad-hoc; si lo ejecutayacc -v, obtendráy.outputuna gramática agradable que lo muestra&&y||combina listas, y las listas finalmente se componen de tuberías (y no al revés); tl; dr;A && B | Ces lo mismo queA && { B | C; }, como se esperaba. No asuma ningún orden de ejecución entreByC; Los comandos en una tubería se ejecutan en paralelo .[...]pruebas y$((...))evaluaciones aritméticas; en particular,||y&&como se usa con la lista de comandos en el lenguaje de shell tiene la misma precedencia , a diferencia de los operadores respectivos enCo en la evaluación aritmética (donde se&&une más estrechamente que||).Respuestas:
Esto es equivalente a
(los comandos del grupo de llaves se unen sin una subshell ). Por lo tanto, la precedencia de
|es mayor (se une más fuerte) que&&y||. Es decir,y
siempre significa que sólo salida de B es que debe darse a C . Puede usar
(...)o{ ... ; }para unir comandos como una sola entidad para la desambiguación si es necesario:Puede probar esto usando algunos comandos diferentes. Si tu corres
entonces obtendrás
atrás:
tr a-z A-Zmayúsculas su entrada , y puede ver que soloecho worldse canalizó en él, mientrasecho hellorealizó por sí solo.Esto se define en la gramática de la cáscara , aunque no está terriblemente claro: la
and_orproducción (para&&/||) se define para tener aapipelineen su cuerpo, mientras quepipelinesolo contienecommand, que no contieneand_or, solo lacomplete_commandproducción puede alcanzarand_or, y solo existe en el nivel superior y dentro de los cuerpos de construcciones estructurales como funciones y bucles.Puede aplicar manualmente esa gramática para obtener un árbol de análisis para un comando, pero Bash no proporciona nada en sí. No conozco ningún shell que vaya más allá de lo que se usa para su propio análisis.
La gramática de shell tiene muchos casos especiales definidos solo semi-formalmente y puede ser una misión acertada. Incluso Bash mismo a veces se ha equivocado , por lo que los aspectos prácticos y el ideal pueden ser diferentes.
Hay analizadores externos que intentan hacer coincidir la sintaxis y producir un árbol, y de ellos recomendaré ampliamente Morbig , que intenta ser el más confiable.
fuente
TL; DR : separadores de listas como
;.&,&&y||decida el orden de análisis.El manual de bash nos dice:
O cómo la wiki de Bash Hacker lo expuso sucintamente
Por lo tanto,
cd ~/screenshots/ && ls screenshot* | head -n 5hay una tubería,ls screenshot* | head -n 5y un comando simplecd ~/screenshots/. Tenga en cuenta que de acuerdo con el manualPor otro lado,
(cd ~/screenshots/ && ls screenshot*) | head -n 5es diferente: tiene una tubería: a la izquierda hay un subshell y a la derecha tienehead -n 5. En este caso, usando la notación de OP sería(A && B) | CTomemos otro ejemplo:
Aquí tenemos una lista
<pipeline1> && <pipeline2>. Como sabemos que el estado de salida de la tubería es el mismo que el del último comando yfalsedevuelve el estado negativo, también conocido como falla,&&no se ejecutará en el lado derecho.Aquí la tubería izquierda tiene un estado de salida exitoso, por lo que se ejecuta la tubería derecha y vemos su salida.
Tenga en cuenta que la gramática de shell no implica el orden de ejecución real. Para citar una de las respuestas de Gilles :
Y del manual bash:
Sobre la base de que en
cd ~/screenshots/ && ls screenshot* | head -n 5elcd ~/screenshots/se ejecutaría en primer lugar,ls screenshot* | head -n 5si el comando anterior tiene éxito, perohead -n 5puede ser un primer proceso dio lugarlsya que están en una tubería.fuente
cd ~/screenshots/ && ls screenshot*ohead -n 5" Bueno, sí, ese es el caso((cd ~/screenshots/ && ls screenshot*) | head -n 5). Pero no dice nada sobre el caso ambiguocd ~/screenshots/ && ls screenshot* | head -n 5que parece ser el punto de la pregunta (con o sin paréntesis).cd ~/screenshots/ && ls screenshot*tendría que procesarse primero porque las&&listas son más altas en el orden de precedencia (basado en la respuesta de l0b0, al menos). ¿Dónde crees que debería mejorar la respuesta?(cd && ls | head)y((cd && ls) | head), podría ser bueno ser explícito sobre a qué te refieres.Aquí es donde se especifica en
bash(1):Entonces,
&&separa las tuberías.fuente
Podrías intentarlo
echo hello && echo world | less. Verá que|tiene mayor prioridad (una tubería de comandos es un comando). Para su segundo ejemplo, NO es lo mismo. Sin embargo, debido a quecdno tiene salida, no verá ninguna diferencia, vía ether.fuente