Приоритет канала (|) и логического и (&&) в bash

В терминале, нажмите Ctrl + G , а затем Введите

17
29.01.2019, 22:25
4 ответа
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-Zupper -case его ввод , и вы можете видеть, что только echo worldбыл передан в него, а echo helloпрошел сам по себе.


Это определяется в грамматике оболочки , хотя и не очень ясно :and_orпродукция (для &&/||)определяется как имеющая aa pipelineв своем теле, в то время как pipelineсодержит только command, который не содержит and_or-только complete_commandпроизводство может достигать and_or, и оно существует только в верхнем уровне и внутри тел структурных конструкций, таких как функции и циклы.

Вы можете вручную применить эту грамматику, чтобы получить дерево синтаксического анализа для команды, но Bash сам по себе ничего не предоставляет. Я не знаю ни одной оболочки, которая делает что-то помимо того, что используется для их собственного синтаксического анализа.

Грамматика оболочки имеет множество особых случаев, определенных лишь полу -формально, и разобраться в них может быть непросто. Даже сам Баш иногда ошибался , так что практичность и идеал могут быть разными.

Существуют внешние синтаксические анализаторы, которые пытаются сопоставить синтаксис и создать дерево, и из них я широко рекомендую Morbig , который пытается быть наиболее надежным.

32
27.01.2020, 19:46

Ты можешь просто попробовать echo hello && echo world | less. Вы увидите, что |имеет более высокий приоритет (Конвейер команд — это команда ). Там для вашего 2-го примера НЕ то же самое. Однако, поскольку cdне имеет вывода, вы не увидите разницы в эфире.

2
27.01.2020, 19:46

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 5cd ~/screenshots/будет выполняться первым, ls screenshot* | head -n 5— если предыдущая команда завершится успешно, но head -n 5может быть первым порожденным процессом, а не ls, поскольку они находятся в конвейере.

9
27.01.2020, 19:46

Вот где это указано в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>.

Итак, &&разделяет трубопроводы.

5
27.01.2020, 19:46

Теги

Похожие вопросы