надежный код возврата фонового процесса

Давайте предположим следующий фрагмент кода bash:

foo > logfile 2>&1 & foo_pid=$! while ps -p$foo_pid do ping -c 1 localhost done wait $foo_pid if [[ $? == 0 ]] then echo "foo success" fi 

Можно ли предположить, что $? действительно содержит код возврата foo а не код возврата ping ? Если ответ на этот вопрос: «Вы не можете этого принять». то как я могу изменить этот кусок кода, чтобы убедиться, что $? всегда содержит код возврата foo ?

3 Solutions collect form web for “надежный код возврата фонового процесса”

С помощью bash вас будет эта гарантия, если вы не запустили другое фоновое задание (и остерегайтесь того, что фоновые задания могут быть запущены с помощью & а также с coproc и с заменой процесса) между foo & и wait .

POSIX требует, чтобы оболочка запоминала статус выхода не менее 25 заданий после их исчезновения , но bash помнит намного больше.

Теперь, если вы это сделаете:

 foo & pid=$! ... bar & wait "$pid" 

У вас нет гарантии, что bar не будет присвоен тот же pid, что и foo (если foo закончил с помощью bar времени), так что, хотя это маловероятно, wait "$pid" может дать вам статус выхода из bar .

Вы можете воспроизвести его с помощью:

 bash -c '(exit 12; foo) & pid=$! while : bar & [ "$pid" != "$!" ]; do :;done wait "$pid"; echo "$?"' 

который (в конце концов) даст вам 0 вместо 12 .

Чтобы избежать проблемы, одним из способов было бы написать ее как:

 { foo_pid=$! while ps -p "$foo_pid" do ping -c 1 localhost done bar & ... read <&3 ret if [ "$ret" = 0 ]; then echo foo was sucessful. fi } 3< <(foo > logfile 2>&1; echo "$?") 

Да, вы можете рассчитывать на wait "$!" для получения статуса фоновой работы. При запуске в качестве сценария bash автоматически не собирает завершенные фоновые задания. Таким образом, если вы запустите wait , он соберет задание во время wait .

Вы можете проверить это с помощью простого скрипта:

 #!/bin/bash sh -c 'sleep 1; exit 22' & sleep 5 echo "FG: $?" wait %1 echo "BG: $?" 

Что будет выводить:

 FG: 0 BG: 22 

Я считаю, что ваше предположение верно. Вот выдержка из man bash относительно ожидания фоновых процессов.

Если n указывает несуществующий процесс или задание, статус возврата равен 127. В противном случае статус возврата – это статус выхода для последнего процесса или ожидаемого задания.

Так что, возможно, вам стоит проверить на 127

Есть аналогичный вопрос с совершенно другим ответом, чем может помочь.

Сценарий Bash ждет процессов и получает код возврата

изменить 1

Вдохновленный комментариями и ответами @ Стефана, я расширил его сценарий. Я могу начать около 34 фоновых процессов, прежде чем он начнет расшатываться.

tback

 $ cat tback plist=() elist=() slist=([1]=12 [2]=15 [3]=17 [4]=19 [5]=21 [6]=23) count=30 #start background tasksto monitor for i in 1 2 3 4 do #echo pid $i ${plist[$i]} ${slist[$i]} (echo $BASHPID-${slist[$i]} running; exit ${slist[$i]}) & plist[$i]=$! done echo starting $count background echos to test history for i in `eval echo {1..$count}` do echo -n "." & elist[$i]=$! done # wait for each background echo to complete for i in `eval echo {1..$count}` do wait ${elist[$i]} echo -n $? done echo "" # Now wait for each monitored process and check return status with expected failed=0 for i in 1 2 3 4 do wait ${plist[$i]} rv=$? echo " pid ${plist[$i]} returns $rv should be ${slist[$i]}" if [[ $rv != ${slist[$i]} ]] then failed=1 fi done wait echo "Complete $failed" if [[ $failed = "1" ]] then echo Failed else echo Success fi exit $failed $ 

на моей системе производит

 $ bash tback 14553-12 running 14554-15 running 14555-17 running starting 30 background echos to test history 14556-19 running ..............................000000000000000000000000000000 pid 14553 returns 12 should be 12 pid 14554 returns 15 should be 15 pid 14555 returns 17 should be 17 pid 14556 returns 19 should be 19 Complete 0 Success 
  • Тайм-аут скриптов с использованием USBMount
  • Удалить сценарий научной нотации bash
  • Удалить записи в файле, если одна и та же запись находится в главном файле
  • Подкатегории MV на один уровень, но не root
  • Преобразование многострочных линий в одну строку
  • Машиночитаемое количество обновлений? Альтернатива / usr / lib / update-notifier / apt-check?
  • awk: принудительное возвращение статуса?
  • как сделать большую командную строку, разбитую на две строки, выполняться как одна строка внутри скрипта
  • Как получить детерминированный полный сброс всех правил iptables?
  • Найти все репозитории git, которые не содержат ни одного из .gitignore и .gitattributes
  • Bash: Как сохранить конкретную строку вывода CLI в файл?
  • Linux и Unix - лучшая ОС в мире.