Настройка pipefail для одной команды

18

Мне нужно выполнить ряд командных командных оболочек из не-BASH-скрипта (а именно PHP-скрипта), например:

command1 | command2 | command3

так что, если происходит command1сбой с ненулевым кодом выхода, каждая другая команда тоже не выполняется. Пока что я придумал:

set -o pipefail && command1 | command2 | command3

Но даже при том, что это работает отлично от терминала, это производит это, если выполнено от сценария:

sh: 1: set: недопустимый параметр -o pipefail

Десмонд Хьюм
источник
Похоже, что /bin/shне нравится set -o pipefail. Это на самом деле bashзамаскированный, или это другая оболочка? Когда bashзапускается как /bin/sh, он принимает set -o pipefail?
Джонатан Леффлер
@JonathanLeffler Когда я запускаю, /bin/sh set -o pipefailон говорит /bin/sh: 0: Can't open set(то же самое с sudo). Надеюсь, я проверил это правильно. Система Ubuntu 12.
Десмонд Хьюм
Вам нужно попробовать /bin/sh -c "set -o pipefail"; как бы то ни было, оболочка пыталась выполнить скрипт в текущем каталоге setи не нашла его.
Джонатан Леффлер
@JonathanLeffler /bin/sh -c "set -o pipefail"не работает, но bash -c "set -o pipefail"работает.
Десмонд Хьюм
Итак, ваша проблема в том, что скрипт запускается, /bin/shкоторый не распознает set -o pipefail. Следовательно, вам нужно убедиться, что скрипт запускается /bin/bashвместо /bin/sh. Или, если вы уверены, смелый - и, вероятно, безрассудный - смените /bin/shего на ссылку или копию /bin/bashвместо того, с какой оболочкой он связан или является копией. Если вы уверены, что /bin/shэто так bash, то вы используете поведение, которое bashне раскрывается при запуске как /bin/sh; использовать bashкак bash.
Джонатан Леффлер

Ответы:

18

Из командной строки Bash вам нужно будет вызывать подоболочку, чтобы избежать pipefailее последующей настройки:

$ (set -o pipefail && command1 | command2 | command3)

Это ограничит влияние pipefailопции на подоболочку, создаваемую скобками (...).

Настоящий пример:

$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active

Если вы используете явный вызов оболочки с -cопцией, вам не нужна подоболочка, с bashили с shпсевдонимом bash:

$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active

Поскольку ваша опция shне принимает эту pipefailопцию, я должен был бы предположить, что она является какой-то более старой или модифицированной версией bash- или что это фактически какая-то другая оболочка.

thkala
источник
1
Является ли $в первой части часть команды это просто командная строка? Пробовал в обе стороны, на самом деле не сработало. bash -cСпособ всегда работает, не слишком элегантный Тхо ..
Desmond Hume
5

Не уверен, почему это не было упомянуто выше, но это можно явно сбросить pipefail, используя set +o pipefail.

set -o pipefail
command1 | command2 | command3
set +o pipefail

Если вы выполняете фрагмент и не знаете о pipefailуже установленном, вы можете использовать это с подоболочками, как предлагалось ранее:

# explicitly execute with pipefail set
(set -o pipefail ; command1 | command2 | command3 )
# explicitly execute with pipefail unset
(set +o pipefail ; command1 | command2 | command3 )
robbat2
источник
0

Вы можете использовать $ (command1) в сочетании с $? :

a=$(echo "a")
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Отпечатки "abc"

a=$(ls unexitingDir)
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Отпечатки "".

«[$? -eq 0] &&» означает, что следующая команда выполняется, только если предыдущая была успешной.

Это не отвечает на ваш вопрос, но это решение вашей проблемы.

cglacet
источник
Означает ли это, что мне всегда нужно хранить выходные данные каждой из команд в переменной?
Десмонд Хьюм
Всегда я не знаю, но с моим решением да, вы будете (если вам это нужно для вашей следующей команды). Если только вы не можете просто написатьcommand1 && command2 && command3
cglacet