cd ~/screenshots/ && ls screenshot* | head -n 5
Это эквивалентно
cd ~/screenshots && { ls screenshot* | head -n 5 ; }
(скобки группируют команды вместе без подоболочки). Таким образом, приоритет |
выше, (связывает прочнее ), чем &&
и ||
. То есть
A && B | C
и
A || B | C
всегда означает, что только продукция B должна передаваться C . Вы можете использовать (...)
или {... ; }
, чтобы объединить команды вместе как единое целое для устранения неоднозначности, если это необходимо:
{ A && B ; } | C
A && { B | C ; } # This is the default, but you might sometimes want to be explicit
Вы можете проверить это с помощью различных команд. Если вы запустите
echo hello && echo world | tr a-z A-Z
тогда вы получите
hello
WORLD
back:tr a-z A-Z
upper -case его ввод , и вы можете видеть, что только echo world
был передан в него, а echo hello
прошел сам по себе.
Это определяется в грамматике оболочки , хотя и не очень ясно :and_or
продукция (для &&
/||
)определяется как имеющая aa pipeline
в своем теле, в то время как pipeline
содержит только command
, который не содержит and_or
-только complete_command
производство может достигать and_or
, и оно существует только в верхнем уровне и внутри тел структурных конструкций, таких как функции и циклы.
Вы можете вручную применить эту грамматику, чтобы получить дерево синтаксического анализа для команды, но Bash сам по себе ничего не предоставляет. Я не знаю ни одной оболочки, которая делает что-то помимо того, что используется для их собственного синтаксического анализа.
Грамматика оболочки имеет множество особых случаев, определенных лишь полу -формально, и разобраться в них может быть непросто. Даже сам Баш иногда ошибался , так что практичность и идеал могут быть разными.
Существуют внешние синтаксические анализаторы, которые пытаются сопоставить синтаксис и создать дерево, и из них я широко рекомендую Morbig , который пытается быть наиболее надежным.
Ты можешь просто попробовать echo hello && echo world | less
. Вы увидите, что |
имеет более высокий приоритет (Конвейер команд — это команда ). Там для вашего 2-го примера НЕ то же самое. Однако, поскольку cd
не имеет вывода, вы не увидите разницы в эфире.
TL;DR:список разделителей, таких как ;
. &
, &&
и ||
определяют порядок синтаксического анализа.
Руководство bash говорит нам:
AND and OR lists are sequences of one or more pipelines separated by the && and || control operators, respectively.
Или как вики Bash Hacker кратко выразили это
<PIPELINE1> && <PIPELINE2>
Таким образом, в cd ~/screenshots/ && ls screenshot* | head -n 5
есть один конвейер-ls screenshot* | head -n 5
и одна простая команда cd ~/screenshots/
. Обратите внимание, что согласно руководству
Each command in a pipeline is executed as a separate process (i.e., in a subshell).
С другой стороны, (cd ~/screenshots/ && ls screenshot*) | head -n 5
отличается -у вас есть один конвейер :слева есть подоболочка, а справа у вас head -n 5
. В этом случае, используя обозначения OP, это будет(A && B) | C
Возьмем другой пример:
$ echo foo | false && echo 123 | tr 2 5
$
Здесь у нас есть один список <pipeline1> && <pipeline2>
. Поскольку мы знаем, что статус выхода конвейера такой же, как и у последней команды, а false
возвращает отрицательный статус, то есть сбой, &&
не будет выполняться с правой стороны.
$ echo foo | true && echo 123 | tr 2 5
153
Здесь левый конвейер имеет статус успешного завершения, поэтому правый конвейер выполняется, и мы видим его выходные данные.
Обратите внимание, что грамматика оболочки не подразумевает фактический порядок выполнения.Цитируя один из ответов Жиля:
Piped commands run concurrently. When you run ps | grep …, it's the luck of the draw (or a matter of details of the workings of the shell combined with scheduler fine-tuning deep in the bowels of the kernel) as to whether ps or grep starts first, and in any case they continue to execute concurrently.
И из руководства по bash:
AND and OR lists are executed with left associativity.
Исходя из того, что в cd ~/screenshots/ && ls screenshot* | head -n 5
cd ~/screenshots/
будет выполняться первым, ls screenshot* | head -n 5
— если предыдущая команда завершится успешно, но head -n 5
может быть первым порожденным процессом, а не ls
, поскольку они находятся в конвейере.
Вот где это указано вbash(1)
:
SHELL GRAMMAR
[...]
Pipelines
A pipeline is a sequence of one or more commands separated by one of
the control operators | or |&.
[...]
Lists
A list is a sequence of one or more pipelines separated by one of the
operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or
<newline>.
Итак, &&
разделяет трубопроводы.