призупинення bash-скрипту до завершення попередніх команд


20

У мене є сценарій bash, який виглядає наступним чином:

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Я хотів би створити ще один цикл після першого, щоб продовжити ще 30. Наприклад

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Я хотів би, щоб перший набір робіт закінчився перед початком нового набору. Але через nohupце здається, що всі вони працюють одночасно.

У мене є те, nohupщо я віддалено входжу на свій сервер і запускаю там роботи, а потім закриваю баш. Чи є альтернативне рішення?


1
Шукайте в посібнику для waitвбудованого.
Satō Katsura

Відповіді:


22

Ви хочете скористатися waitкомандою, щоб зробити це для вас. Ви можете або зафіксувати всі ідентифікатори дітей, які обробляють, і спеціально їх чекати, або якщо вони є єдиними фоновими процесами, які створює ваш сценарій, ви можете просто зателефонувати waitбез аргументу. Наприклад:

#!/bin/bash
# run two processes in the background and wait for them to finish

nohup sleep 3 &
nohup sleep 10 &

echo "This will wait until both are done"
date
wait
date
echo "Done"

6

Кілька пунктів:

  • Якщо ваша мета nohupполягає в тому, щоб запобігти віддаленому виходу оболонки не вбивати ваших робочих процесів, вам слід скористатися nohupсамим сценарієм, а не окремими робочими процесами, які він створює.

  • Як пояснено тут , nohupлише перешкоджає процесам прийому SIGHUP та взаємодії з терміналом, але він не порушує взаємозв'язок між оболонкою та її дочірніми процесами.

  • Через пункт вище, з або без nohup, простий waitміж двома forпетлями призведе до того, що другий forбуде виконаний лише після того, як всі дочірні процеси, розпочаті першою, forзакінчилися.

  • З простим wait:

    чекають усі активні в даний час дочірні процеси, і статус повернення дорівнює нулю.

  • Якщо вам потрібно запустити другий, forлише якщо в першому не було помилок, вам потрібно буде зберегти PID кожного працівника $!та передати їх усім wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }

На сервері можуть працювати інші завдання. Тому я хотів би лише почекати моєї партії .. це R-сценарії, тому вони запускаються під командою Rабо cc1plusв topкоманді
masfenix

Також я хотів би використовувати nohup всередині, щоб запустити всі команди в "паралельно". в основному це моделювання наукової програми. Я хочу запустити 180 симуляцій в цілому, але партіями по 60. Лічильник також повинен перейти від 1 до 180. Якщо я їх робити по одному, це займе занадто багато часу.
masfenix

waitзмушує bashчекати фонових завдань, які вона породила сама, нічого іншого. Тут може виникнути певна плутанина - ці forпетлі, ви зберегли їх у файл і викликали їх як сценарій (що я припускав, через ##scriptрядок), або ви набираєте їх вручну в терміналі?
Матей Девід

-1

Використовуйте fgвбудований. Він чекає, поки фонові процеси закінчаться.

Спробуйте help fgдетальніше.


Сценарій працює без контролю роботи.
Kusalananda

-1

Якщо ви вставите щось на зразок наступного сегмента коду між двома forциклами, це може допомогти.

flag=0

while [ flag -eq 0 ]
do
  ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null
  flag=${?}
  sleep 10
done

Звичайно, якщо у вашої програми Rscriptє шанс не завершити успішно і затриматися, у другого циклу може не виникнути шансів запуститись. Кодовий сегмент вище передбачає, що всі процеси з ідентифікатором Rscript --vanillaзавершаться і зникнуть належним чином. Не знаючи, що робить ваша програма та як вона працює, я повинен покластися на це припущення.

EDIT

Зважаючи на коментарі, це краще відповідає вашим потребам. (він включає ваш оригінальний код, а також логіку перевірки завершення)

for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
pids[$i]=${!}
done

flag=0

while [ flag -eq 0 ] 
do
  for PID in $(echo ${pids[@]})
  do
    flag=1
    ps -ef | grep ${PID} | grep -v grep >/dev/null; r=${?}
    if [ ${r} -eq 0 ]
    then 
      flag=0
    fi
  done
done

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Ім'я процесу в topшоу відображається або Rіноді, або cc1plus.
masfenix

У такому випадку вам потрібно буде знайти загальний знаменник, який відображається у ps -efсписку. Або після кожної nohupкоманди запишіть PID до змінної (бажано масиву) echo ${!}і перевірте, чи не існує цієї групи PID. Коли всі вони зникнуть, ви можете перейти до другого forциклу
Мельбурслан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.