Bash & (амперсанд) оператор

Я пытаюсь запустить 3 команды параллельно в оболочке bash:

$ (first command) & (second command) & (third command) & wait

Проблема в том, что если, например, first command завершается ошибкой, код выхода будет 0 (я думаю, потому что wait завершается успешно).

Желаемое поведение состоит в том, что в случае сбоя одной из команд код выхода будет ненулевым (и в идеале другие запущенные команды будут остановлены).

Как я мог этого добиться?

Обратите внимание, что я хочу запускать команды параллельно!


person Misha Moroshko    schedule 13.02.2012    source источник


Ответы (4)


лучшее, что я могу придумать, это:

first & p1=$!
second & p2=$!
...

wait $p1 && wait $p2 && ..

or

wait $p1 || ( kill $p2 $p3 && exit 1 )
...

однако это по-прежнему обеспечивает порядок проверки процессов, поэтому, если третий немедленно выйдет из строя, вы не заметите этого, пока не закончатся первый и второй.

person Karoly Horvath    schedule 13.02.2012

Вы должны использовать && вместо &. например:

first command && second command && third command && wait

Однако это НЕ будет запускать вашу команду параллельно, так как выполнение каждой последующей команды будет зависеть от кода выхода 0 предыдущей команды.

person anubhava    schedule 13.02.2012
comment
Я думаю, что это будет работать с точки зрения кода возврата, но не будет выполнять команды параллельно. - person jcollado; 13.02.2012
comment
Согласен и сделал пометку в моем ответе. Однако, если команды выполняются параллельно, вы не можете проверить код выхода, потому что предыдущая команда не завершилась при запуске второй. - person anubhava; 13.02.2012
comment
Основным ограничением здесь является запуск команд параллельно. Я не возражаю заменить этот однострочный сценарий более сложным bash-скриптом, если команды будут выполняться параллельно, а код выхода будет ненулевым в случае сбоев. - person Misha Moroshko; 13.02.2012
comment
Пожалуйста, поймите, что если команды выполняются параллельно (или в фоновом режиме), то статус выхода не может быть немедленно доступен, вам придется ждать завершения выполнения команд. - person anubhava; 14.02.2012

Это может сработать для вас:

parallel -j3 --halt 2 <list_of_commands.txt

Это запустит 3 команды параллельно.

Если какое-либо запущенное задание завершается сбоем, оно убивает оставшиеся запущенные задания, а затем останавливается, возвращая код выхода неудачного задания.

person potong    schedule 13.02.2012
comment
Он будет запускать 3 команды параллельно, но не будет соответствовать требованиям кода выхода OP. - person anubhava; 14.02.2012
comment
@MishaMoroshko погуглите gnu parallel. @anubhava из параллельного руководства --halt 2 Kill off all jobs immediately and exit without cleanup. The exit status will be the exit status from the failing job. - person potong; 15.02.2012

Приведенная ниже функция оболочки будет ждать завершения всех PID, переданных в качестве аргументов, возвращая 0, если все PID выполнены без ошибок.

Первый существующий PID с ошибкой приведет к уничтожению PID, следующих за ним, а код выхода, вызвавший ошибку, будет возвращен функцией.

wait_and_fail_on_first() {
  local piderr=0 i
  while test $# -gt 0; do {
    dpid="$1"; shift
    wait $dpid || { piderr=$?; kill $@; return $piderr ;}
  } done
}

Вот как это использовать:

(first command) & pid1=$!
(second command) & pid2=$!
(third command) & pid3=$!

wait_and_fail_on_first $pid1 $pid2 $pid3 || {
  echo "PID $dpid failed with code $?"
  echo "Other PIDs were killed"
}
person Elifarley    schedule 10.08.2020