приостановка скрипта 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

Я хотел бы создать еще один цикл for после первого, чтобы продолжить еще на 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потому что я удаленно войти в систему на моем сервере и начать работу там, а затем закрыть мой Bash. Есть ли альтернативное решение?


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. Если я сделаю их по одному, это займет слишком много времени.
Масфеникс

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

-1

Используйте fgвстроенный. Он ожидает завершения фоновых процессов.

Попробуйте help fgдля деталей.


Скрипт работает без контроля задания.
Кусалананда

-1

Если вы вставите что-то вроде следующего сегмента кода между двумя forциклами, это может помочь.

flag=0

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

Конечно, если у вашего приложения Rscriptесть шанс не завершиться успешно и задержаться, ваш второй цикл for может не иметь возможности для запуска. Сегмент кода выше предполагает, что все процессы с идентификатором Rscript --vanillaзавершатся и исчезнут правильно. Не зная, что делает ваше приложение и как оно работает, я должен полагаться на это предположение.

РЕДАКТИРОВАТЬ

В свете комментариев, это будет лучше соответствовать вашим потребностям. (содержит исходный код, а также логику проверки завершения)

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циклу
MelBurslan
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.