Цепочка команд Bash не завершается, как ожидается

Во время работы над цепочкой инструментов проекта стало очевидно, что я не понимаю bash списков.

Из руководства:
"руководство": man bash

Списки:

Список — это последовательность из одного или нескольких конвейеров, разделенных одним из операторов ;, &, && или ||,

[...]

Из этих операторов списка && и || имеют равный приоритет, за которым следует ; и &, которые имеют одинаковый приоритет.

[...]

Списки И и ИЛИ — это последовательности одного или нескольких конвейеров, разделенные знаками && и || операторы управления соответственно. Списки И и ИЛИ выполняются с левой ассоциативностью. Список AND имеет форму

команда1 && команда2

команда2 выполняется тогда и только тогда, когда команда1 возвращает нулевой статус выхода.

Список ИЛИ имеет вид

команда1 || команда2

команда2 выполняется тогда и только тогда, когда команда1 возвращает ненулевой статус выхода. Статус возврата списков И и ИЛИ — это статус выхода последней команды, выполненной в списке.
[Форматирование]

Вместо кода, который выглядит так:

command1

if [ $? -eq 0 ];
then
    command2
fi;

Мы можем просто сделать это:

command1 && command2

В одном из имеющихся у меня скриптов есть код, функционально эквивалентный этому:

#!/bin/bash

s () { return 0; }
f () { return 1; }
l () { echo "Y"; }

#Why does this output "Y"?
f && f || true && s && l

#This does what I want:
f && { f; s && l; }

В приведенном выше примере я ожидаю (и очень хочу), чтобы f || true && s && l выполнялся только в том случае, если f не выйдет из строя. Но, увы, я должен использовать f && { f; s && l; }, чтобы получить желаемую функциональность.

Что я неправильно понимаю? Почему цепочка «продолжает идти» после первого &&?

Разве цепочка команд не должна прекращать выполнение после f &&, потому что "команда2 выполняется тогда и только тогда, когда команда1 возвращает ненулевой статус выхода"?


PS: я ожидаю, что это будет работать так.

if (f == 0) {
    if (f != 0) {
        if (0 == 0) {
            if (s == 0) {
                l;
                }
            }
        }
     }

person J. Allan    schedule 03.12.2016    source источник
comment
Равный приоритет, левая ассоциативность: f && f || true && s && l анализируется как (((f && f) || true) && s) && l (недействительный синтаксис оболочки, круглые скобки используются только для демонстрации). ... || true всегда верно, поэтому s выполняется всегда.   -  person melpomene    schedule 03.12.2016
comment
@melpomene: Ой! Похоже, я не понимаю равного приоритета. (Обычно я использую круглые скобки в операторах if.)   -  person J. Allan    schedule 03.12.2016
comment
Кроме цепочки && или цепочки ||, лучше всего использовать явный оператор if. Смешивание двух никогда не будет более четким и часто будет более подвержено ошибкам.   -  person chepner    schedule 03.12.2016
comment
@chepner: Спасибо. В этом есть смысл. Что ты думаешь об использовании {} для форсирования определенного порядка, как в коде, который я сейчас использую?   -  person J. Allan    schedule 03.12.2016
comment
Это правильно, но я не думаю, что это так же читабельно, как if f; then f; s && l; fi (которое в скрипте не будет помещено в одну строку, а будет правильно разделено и с отступом).   -  person chepner    schedule 03.12.2016
comment
@chepner: Поскольку у меня есть 3 строки, которые похожи, но не идентичны, на мой взгляд, использование {} там, где это уместно, делает его немного чище. (Я не знал, что вы можете сделать if f; ..., так что спасибо, что указали на это. Раньше я бы сделал f; if [ $? -eq 0 ]; ....)   -  person J. Allan    schedule 03.12.2016


Ответы (1)


Почему выводится "Y"?

f && f || true && s && l
is the same as
( 
  (
    ( 
      (
        f && f
      ) || true 
    ) && s 
  ) && l
)

но с=ложь

( 
  (
    f && f
  ) || true 
) && s
-> false

Фактически

f && f || true && s && l -> l

О PS

not (f=0) || not (f!=0) || not (0=0) || not (s=0) ||  l
person V. Michel    schedule 03.12.2016
comment
Спасибо за ответ, но не могли бы вы добавить небольшое пояснение? Я не уверен, почему f && b && c эквивалентно ((f && b) && c)... - person J. Allan; 03.12.2016
comment
@JefréN, потому что это левоассоциативно, вы читаете слева направо. Это зависит от языка, но встречается чаще всего. Удачи в вашем проекте. - person V. Michel; 04.12.2016
comment
Почему он не завершает работу после сбоя f? Разве остальная часть команды не должна выполняться? - person J. Allan; 04.12.2016
comment
@JefréN Да, важно, когда первое условие не выполнено, ему не нужно продолжать. Пример false && echo 2, никогда не напечатает 2. Это двойственность с ||, true || echo 2 никогда не напечатает 2, потому что первое условие истинно. - person V. Michel; 04.12.2016
comment
Вы пытаетесь сказать, что, поскольку && и || имеют одинаковый приоритет, проверяются все возможные комбинации? - person J. Allan; 04.12.2016
comment
@JefréeN Не все комбинации проверены. - person V. Michel; 04.12.2016