Bash: почему ожидание преждевременно возвращается с кодом 145 - PullRequest
0 голосов
/ 21 ноября 2018

Эта проблема очень странная, и я не могу найти документацию по этому вопросу в Интернете.В следующем фрагменте кода я просто пытаюсь запустить несколько подпроцессов параллельно, печатая что-то, когда они выходят, и собирая / печатая свой код выхода в конце.Я обнаружил, что без перехвата SIGCHLD все работает, как я и ожидал, однако, когда я улавливаю сигнал, все обрывается.Вот код:

#!/bin/bash

#enabling job control
set -m

cmd_array=( "$@" )         #array of commands to run in parallel
cmd_count=$#               #number of commands to run
cmd_idx=0;                 #current index of command
cmd_pids=()                #array of child proc pids
trap 'echo "Child job existed"' SIGCHLD #setting up signal handler on SIGCHLD

#running jobs in parallel
while [ $cmd_idx -lt $cmd_count ]; do
  cmd=${cmd_array[$cmd_idx]} #retreiving the job command as a string
  eval "$cmd" &
  cmd_pids[$cmd_idx]=$!            #keeping track of the job pid
  echo "Job #$cmd_idx launched '$cmd']"
  (( cmd_idx++ ))
done

#all jobs have been launched, collecting exit codes
idx=0
for pid in "${cmd_pids[@]}"; do
  wait $pid
  child_exit_code=$?
  if [ $child_exit_code -ne 0 ]; then
    echo "ERROR: Job #$idx failed with return code $child_exit_code. [job_command: '${cmd_array[$idx]}']"
  fi
  (( idx++ ))
done

Вы можете сказать, что что-то не так, если попытаетесь выполнить следующую команду:

./parallel_script.sh "sleep 20; echo done_20" "sleep 3; echo done_3"

Интересная вещь здесьчто вы можете сказать, как только вызывается обработчик сигнала (когда спит 3), ожидание (которое ожидает в спящем режиме 20) сразу прерывается кодом возврата 145. Я могу сказать, что спящий режим 20 все еще работает, даже еслипосле того, как сценарий сделан.Я не могу найти документацию о таком коде возврата от ожидания.Может кто-нибудь пролить свет на то, что здесь происходит?

(Кстати, если я добавлю цикл while, когда жду и продолжаю ждать, пока код возврата 145, я действительно получаю ожидаемый результат)

1 Ответ

0 голосов
/ 21 ноября 2018

Благодаря @muru я смог воспроизвести «проблему», используя гораздо меньше кода, который вы можете увидеть ниже:

#!/bin/bash

set -m
trap "echo child_exit" SIGCHLD

function test() {
 sleep $1
 echo "'sleep $1' just returned now"
}

echo sleeping for 6 seconds in the background
test 6 &
pid=$!
echo sleeping for 2 second in the background
test 2 &
echo waiting on the 6 second sleep
wait $pid
echo "wait return code: $?"

Если вы запустите это, вы получите следующий вывод:

linux:~$ sh test2.sh
sleeping for 6 seconds in the background
sleeping for 2 second in the background
waiting on the 6 second sleep
'sleep 2' just returned now
child_exit
wait return code: 145
lunux:~$ 'sleep 6' just returned now

Объяснение:

Как указал @muru " Когда команда завершается на фатальном сигнале с номером N, Bash использует значение 128 + Nв качестве состояния выхода."(см. руководство пользователя Bash по состоянию на выходе ).Теперь, что вводит меня в заблуждение, это «фатальный» сигнал.Я искал команду, которая где-нибудь не сработала бы, когда ничего не получалось.

Копаем немного глубже в Руководство Bash по сигналам : " Когда Bash ожидает асинхронную команду через ожиданиевстроенный прием сигнала, для которого установлена ​​ловушка, заставит встроенную функцию ожидания немедленно вернуться со статусом выхода больше 128, сразу после чего ловушка будет выполнена."

Итаку вас есть то, что происходит в сценарии выше:

  1. sleep 6 начинается в фоновом режиме
  2. sleep 3 запускается в фоновом режиме
  3. wait начинает ожидание sleep 6
  4. sleep 3 завершается, и прерывание SIGCHLD при прерывании ожидания прерывания возвращает 128 + SIGCHLD = 145
  5. мой сценарий завершается, так как он больше не ждет
  6. фон sleep 6 завершается, поэтому "сон 6" только что вернулся "после того, как скрипт уже вышел
...