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

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

Отвечаяэтот вопросЯ обнаружил очень забавную (и тонкую) разницу между поведением в 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

Как видите, выполнение alias 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имеет другой приоритет, чем in zsh--- Я имею в виду, что команда, похоже, читается как

(cd /tmp && echo A) & 

в bashи как

cd /tmp && (echo A &) 

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

решение1

Различное, документированное поведение вzshmisc

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

решение2

В нем зарыта zshmisc(1)следующая строка:

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

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

$ echo $foo $bar

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

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

Связанный контент