หยุดสคริปต์ bash ชั่วคราวจนกว่าคำสั่งก่อนหน้าจะเสร็จสิ้น


20

ฉันมีสคริปต์ทุบตีที่มีลักษณะดังนี้:

##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เพราะฉันลงชื่อเข้าใช้เซิร์ฟเวอร์ของฉันจากระยะไกลและเริ่มงานที่นั่นแล้วปิด bash ของฉัน มีทางเลือกอื่นหรือไม่?


1
ค้นหาคู่มือสำหรับwaitbuiltin
Satō Katsura

คำตอบ:


22

คุณจะต้องการใช้waitคำสั่งเพื่อทำสิ่งนี้ให้คุณ คุณสามารถจับภาพ ID กระบวนการเด็กทั้งหมดและรอพวกเขาโดยเฉพาะหรือถ้าพวกเขาเป็นเพียงกระบวนการพื้นหลังสคริปต์ของคุณสร้างคุณสามารถโทรได้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บรรทัด) หรือคุณพิมพ์ด้วยมือใน terminal หรือไม่
Matei David

-1

ใช้fgbuiltin มันจะรอจนกว่ากระบวนการพื้นหลังจะเสร็จสิ้น

ลอง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จะเสร็จสมบูรณ์และหายไปอย่างถูกต้อง โดยไม่ทราบว่าแอปพลิเคชันของคุณทำงานอย่างไรและทำงานอย่างไรฉันต้องเชื่อตามสมมติฐานนี้

แก้ไข

ในแง่ของความคิดเห็นสิ่งนี้จะเหมาะกับความต้องการของคุณ (มันมีรหัสต้นฉบับของคุณเช่นเดียวกับตรรกะการตรวจสอบเสร็จสมบูรณ์)

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.