Приоритет && против & в bash и zsh

9

Отвечая на этот вопрос, я обнаружил очень забавную (и тонкую) разницу между поведением в bashи zsh:

В bash:

romano@RRyS:~$ pwd
/home/romano
romano@RRyS:~$ alias x="cd /bin && ./echo A >/dev/null  &"
romano@RRyS:~$ x
[1] 16611
romano@RRyS:~$ pwd
/home/romano

Как видите, выполнение псевдонима xвыполняется в подоболочке, поэтому текущий каталог не изменяется.

Не в zsh:

[romano:~] % pwd
/home/romano
[romano:~] % alias x="cd /bin && ./echo A >/dev/null &"
[romano:~] % x
[1] 16744
[1]  + 16744 done       ./echo A >/dev/null                                    
1& [romano:/bin] % pwd
/bin
[romano:/bin] % 

здесь каталог изменен.

Кажется, что у &in bashприоритет другой, чем у zsh--- Я имею в виду, что команда читается как

(cd /tmp && echo A) & 

в bashи как

cd /tmp && (echo A &) 

в zsh. Это правильно или причина другого поведения - другая?

Rmano
источник

Ответы:

9

Другое, документированное поведение в zshmisc

Список представляет собой последовательность из нуля или более подсписков, в котором каждый подсписок завершается ;, &, &|, &!, или перевод строки. Этот терминатор может опционально быть исключен из последнего подсписка в списке, когда список отображается как сложная команда внутри (...)или {...}. Когда подсписок завершается символом ;или символом новой строки, оболочка ожидает его завершения, прежде чем выполнить следующий подсписок. Если подсписок завершается с помощью &,, &|или &!, оболочка выполняет последний конвейер в нем в фоновом режиме и не ожидает его завершения (обратите внимание на отличие от других оболочек, которые выполняют весь подсписок в фоновом режиме). Заземленный конвейер возвращает нулевое состояние.

llua
источник
3

Похоронена в zshmisc(1)следующей строке:

Если подсписок завершается символом &',& | 'или `&!', Оболочка выполняет последний конвейер в нем в фоновом режиме,

Хотя в нем конкретно не указано, что другие конвейеры в подсписке выполняются в текущей оболочке, похоже, это именно то, что подразумевается, и наблюдаемое вами поведение поддерживает эту интерпретацию. Например:

$ echo $foo $bar

$ foo=3 && bar=5 && sleep 1 &
$ echo $foo $bar
3 5

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

chepner
источник