PIPESTATUS игнорирует отрицание?

Я только что нашел следующие результаты в bash (версия 4.2.25(1)-релиз):

$ true; echo "${PIPESTATUS[@]}"
0
$ ! true; echo "${PIPESTATUS[@]}"
0
$ false; echo "${PIPESTATUS[@]}"
1
$ ! false; echo "${PIPESTATUS[@]}"
1
$ true && false; echo "${PIPESTATUS[@]}"
1
$ true && ! false; echo "${PIPESTATUS[@]}"
1

Так, $PIPESTATUS кажется, игнорирует отрицания во всех случаях. Это известная проблема? Я не мог ничего найти об этом. Или это желаемое поведение? Если так, то в чем причина?

При использовании подоболочки все работает так, как я и ожидал:

$ (true && ! false); echo "${PIPESTATUS[@]}"
0

2 ответа

Решение

! a | b | c интерпретируется как !{a | b | c;} оболочкой, а не как {! a;} | b | c,

Индивидуальные статусы выхода из команды хранятся в ${PIPESTATUS[@]},

$? относится к состоянию выхода всей команды, включая !,

Вы можете заставить (! a) | b | c фактически порождая подоболочку. например

$ true; echo "${PIPESTATUS[@]}"
0
$ (! true); echo "${PIPESTATUS[@]}"
1
$ false; echo "${PIPESTATUS[@]}"
1
$ (! false); echo "${PIPESTATUS[@]}"
0

Я думаю, что это поведение предназначено и становится более ясным, если смотреть с полным конвейером:

a | b | c | d ; echo "${PIPESTATUS[@]}"

Это покажет статусы выхода процессов a, b, c, а также d,

Отрицания теперь применяются только к состоянию завершения всего конвейера:

! a | b | c | d ; echo "${PIPESTATUS[@]}"

Не допускается отрицание частей трубопровода:

a | ! b | c | d   # Syntax error at "| !"

Благодаря такому подходу труба ассоциируется сильнее, чем отрицание (можно сказать, что это ! (a | b | c | d) на уровне ассоциации), поэтому отрицание не влияет на результаты компонентов канала, поскольку отрицание применяется позже, после оценки конвейера.

Другие вопросы по тегам