Bash จะให้กระบวนการพื้นหลังทำงานอย่างไร แต่รอให้กระบวนการอื่น ๆ ทำงาน


11

ฉันมี (ยัง) อีกwait, &, &&คำถามการควบคุมการไหล ..

ว่าฉันมีสคริปต์บางอย่างเช่นนี้ที่ฉันต้องการทำงานมากที่สุดในเวลาเดียวกันเป็นไปได้:

# may take some hours
something InputA > IrrelevantA &
something InputB > IrrelevantB &

# may take an hour
(
   somethingElse InputA > OutputA &
   somethingElse InputB > OutputB &
)&& combine OutputA OutputB > Result

...morestuff

คำถามที่ 1: ในสคริปต์combineรอให้somethingElseกระบวนการทั้งสองเสร็จสิ้นในขณะที่somethingกระบวนการทั้งสองดำเนินการต่อหรือไม่

คำถามที่ 2: ถ้าไม่ใช่ - และฉันสงสัยว่าไม่ได้ - ฉันcombineจะรอsomethingElseกระบวนการทั้งสองได้อย่างไรในขณะที่somethingกระบวนการข้างต้นยังคงทำงานอยู่เบื้องหลัง

คำตอบ:


13

ในตัวอย่างของคุณcombineคำสั่งจะถูกเรียกใช้ทันทีที่ออกจาก subshell (และให้กระบวนการพื้นหลังล่าสุดเริ่มต้นโดยไม่มีข้อผิดพลาด) เชลล์ย่อยจะออกทันทีหลังจากเริ่มงานเนื่องจากไม่มีwaitคำสั่ง

หากคุณต้องการรันคำสั่งตามค่าส่งคืนของกระบวนการพื้นหลังพร้อมกันสองกระบวนการขึ้นไปฉันไม่สามารถมองเห็นวิธีอื่นนอกจากใช้ไฟล์ชั่วคราวสำหรับค่าส่งคืน นี่เป็นเพราะwaitสามารถส่งคืนค่าส่งคืนของหนึ่งในกระบวนการที่รอ นอกจากนี้เนื่องจากกระบวนการพื้นหลังจะต้องทำงานใน subshells เพื่อรับค่าส่งคืนเลยพวกเขาไม่สามารถเก็บไว้ในตัวแปรได้ คุณสามารถทำได้:

something InputA >IrrelevantA &
something InputB >IrrelevantB &

tmp1=$(mktemp)
tmp2=$(mktemp)

( somethingElse InputA >OutputA; echo $? >"$tmp1" ) &
proc1=$!

( somethingElse InputB >OutputB; echo $? >"$tmp2" ) &
proc2=$!

wait "$proc1" "$proc2"

read ret1 <"$tmp1"
read ret2 <"$tmp2"
[ "$ret1" = 0 && "ret2" = 0 ] && combine OutputA OutputB >Result

rm "$tmp1" "$tmp2"

หากคุณไม่สนใจค่าตอบแทนคุณสามารถเริ่มงานได้ตามปกติแล้วใช้wait:

something InputA >IrrelevantA &
something InputB >IrrelevantB &

somethingElse InputA >OutputA &
proc1=$!

somethingElse InputB >OutputB &
proc2=$!

wait "$proc1" "$proc2"
combine OutputA OutputB >Result

สวัสดีฉันคิดว่าตัวเลือกที่ 2 น่าจะเหมาะกับฉัน ...
สตีเฟ่นเฮนเดอร์สัน

3

หากว่าเปลี่ยนตัวกระบวนการมีประสิทธิภาพมากขึ้นโดยเฉพาะอย่างยิ่งถ้าคุณไม่ต้องการที่จะบันทึกไฟล์OutputAและOutputBและการดูแลเพียงประมาณResult? นี่จะเป็นการประหยัดเวลาโดยเฉพาะอย่างยิ่งเพราะถ้าคุณมี I / O ช้าในการเขียนลงดิสก์การบันทึกไฟล์OutputAและOutputBอาจเป็นขั้นตอนที่ จำกัด อัตรา?

combine  <(somethingElse InputA)  <(somethingElse InputB)  >  Result

การทดแทนกระบวนการช่วยให้คุณสามารถวางคำสั่งไว้ภายใน<(..here..)แทนที่จะบันทึกเอาต์พุตลงในไฟล์จากนั้นอ่านจากมันเป็นอินพุตในขั้นตอน "รวม"

หากหน่วยความจำมีข้อ จำกัด และขนาดoutputAและoutputBมากกว่าสิ่งที่หน่วยความจำสามารถเก็บได้มันจะเอาชนะวัตถุประสงค์ทั้งหมดหรือไม่

จะcombineรอจนกว่ากระบวนการทั้งสองจะเสร็จสมบูรณ์ก่อนที่จะเริ่มทำงานหรือไม่


นี่ไม่ใช่“ อันตราย”; โปรดทำไม่วลีตอบสนองของคุณในรูปแบบของคำถาม อย่างจริงจังคุณได้แนวคิดใหม่มาแล้วและฉันคิดว่ามันค่อนข้างดี ในการตอบสนองต่อคะแนนสองสามข้อของคุณ: combineจะเริ่มทำงานทันทีที่somethingElseคำสั่งสองคำสั่งเริ่มทำงาน แต่ก็ไม่เป็นไรเพราะ<(…)ทุกอย่างเป็นไปได้ ดังนั้นcombineก็จะถูกบังคับให้รอข้อมูลถ้ามันเกินกว่าsomethingElseกระบวนการ และเนื่องจากเป็นท่อขนาดจึงไม่เป็นปัญหา … (ต่อ)
G-Man พูดว่า 'Reinstate Monica'

(ต่อ) …ปัญหาที่สำคัญเพียงอย่างเดียวที่ฉันมีกับคำตอบของคุณคือไม่อนุญาตให้ทำการทดสอบสถานะการออกของsomethingElseกระบวนการ - และยังไม่ชัดเจนว่าเป็นเรื่องสำคัญสำหรับผู้ถามหรือไม่ แต่คำตอบก็ไม่ควรถามคำถามเช่นนั้น
G-Man กล่าวว่า 'Reinstate Monica'

2

คุณสามารถใช้waitคำสั่ง:

(echo starting & sleep 10 & wait) && echo done

คุณสามารถเห็นบรรทัด "เริ่มต้น" เกิดขึ้นได้ทันทีและ "เสร็จสิ้น" จะรอเป็นเวลา 10 วินาที


โดยทั่วไปการรอนั้นจะต้องใช้กระบวนการลูกของเชลล์เดียวกัน เดี๋ยวก่อนนะ
mikeserv

1
@mikeserv คุณกำลังพูดถึงอะไร นั่นคือประเด็น: รอเด็กทุกคนในชั้นย่อยนั้น
psusi

โดยการทดสอบครั้งแรกของฉันงานนี้ ฉันจะลองทำตามบทที่ยิ่งใหญ่ตอนนี้
สตีเฟ่นเฮนเดอร์สัน

ตรง - สำหรับเด็กของเปลือกเดียวกัน - ย่อยเปลือกหอย ควรทำงานสำหรับกระบวนการใด ๆ ที่ไม่พยายามหลบหนี - หรือ daemonize หรืออะไรก็ตาม นั่นคือทั้งหมดที่ฉันหมายถึง - ตราบใดที่กระบวนการของคุณเคารพผู้นำกระบวนการรอไม่เป็นไร แต่ทันทีที่กระบวนการพยายามเป็นผู้นำกระบวนการของตัวเองการรอจะมีปัญหา
mikeserv

0

ที่จริงผมแสดงให้เห็นว่าวิธีการเรียงลำดับของสิ่งนี้อาจจะมีการทำในคำตอบอื่นที่นี่ คำตอบนั้นเป็นคำถามเกี่ยวกับการทำให้มั่นใจว่ามีการบันทึก 2 รายการโดยกระบวนการพื้นหลังดังนั้นฉันจึงแสดงให้เห็นด้วย 10

สคริปต์สาธิต

cat <<-\DEMO >|${s=/tmp/script} 
printf 'tty is %s\nparent pid is %s\npid is pid=%s\n' \
     "$(tty)" "$PPID" "$$"
exec 1>&2 ; nums=$(seq 0 9)
rm ${files=$(printf "/tmp/file%s\n" $nums)}
for n in $nums ; do { for f in $files ; do
    echo "Line $n" >>"$f" ; done
sleep 1 ; } ; done
#END
DEMO

เรียกใช้การสาธิต

s=/tmp/script ;chmod +x $s ;info="$(($s &)2>&- &)"
echo "$info" ; pid="${info##*=}" ; echo
while ps -p $pid >/dev/null ; do sleep 3 ; done
for f in /tmp/file[0-9] ; do
    printf 'path : %s\tline count : %s\n' \
        $f $(<$f wc -l)
done

เอาท์พุท:

tty is not a tty
parent pid is 1
pid is 12123

path : /tmp/file0    line count : 10
path : /tmp/file1    line count : 10
path : /tmp/file2    line count : 10
path : /tmp/file3    line count : 10
path : /tmp/file4    line count : 10
path : /tmp/file5    line count : 10
path : /tmp/file6    line count : 10
path : /tmp/file7    line count : 10
path : /tmp/file8    line count : 10
path : /tmp/file9    line count : 10

ข้างต้นแสดงให้เห็นถึง มันสร้างและเรียกใช้สคริปต์ที่มีชื่อ/tmp/script, chmod'sเป็นปฏิบัติการและวิ่งในของ&background&backgrounded ( subshell )

rms /tmp/file0-9ไฟล์สคริปต์10 และechoesบรรทัดทุกวินาทีในทั้ง 10 ไฟล์ ฉันจับภาพบางส่วน$infoจากกระบวนการปฏิเสธและนำเสนอผ่าน$(command substitution). While psรายงานภาพนิ่งที่$pidฉันจับฉันรู้ว่ามันยังทำงานอยู่ดังนั้นฉันsleep.เมื่อมันเสร็จสมบูรณ์บรรทัดในทั้ง 10 ไฟล์จะถูกนับด้วยwc.

หลังจากที่คุณเรียกใช้กระบวนการด้วยวิธีนี้คุณสามารถปิดกระบวนการหลักดั้งเดิมได้อย่างอิสระและมันจะเก็บไว้ในรถบรรทุก - มันถูกปฏิเสธอย่างมีประสิทธิภาพ นอกจากนี้ยังหมายความคุณไม่สามารถใช้การชุมนุมwaitคำสั่ง แต่รอps'sผลตอบแทนที่ควรจะมีประสิทธิภาพมากขึ้นในกรณีใด ๆ

มูลค่าการกล่าวขวัญผมคิดว่าก็คือกระบวนการที่เป็นจริงในตอนแรกเรียก$(command substitution)และprintfsฉัน$infoฉันต้องการได้อย่างมีประสิทธิภาพดังนั้นฉันสามารถควบคุมได้ แต่ทันทีที่มันลดลงเทอร์มินัลเอาต์พุตด้วยexec 1>&2(ซึ่งถูกปิดใน subshell เดียวกันด้วย2>&-)กระบวนการจะหนีและฉันต้องรอรอบอีกด้านหนึ่ง ค่อนข้างดีที่สุดในโลกทั้งสองโดยเฉพาะอย่างยิ่งถ้าคุณใช้มันเพื่อจัดการกับอินพุตท่อตราบใดที่คุณสามารถปิดล้อมการเปลี่ยนเส้นทางและผู้นำกระบวนการทั้งหมด

ทุกอย่างเป็นเพียงการสาธิตที่นี่ สิ่งที่คุณต้องใช้ในการทำงานนี้คือสคริปต์อันดับต้น ๆ และ:

info="$(($script_path &)2>&- &)"    

หมายเหตุ:นี่จะพิมพ์ไปที่เทอร์มินัลสิ่งที่ฉันต้องการแสดงให้เห็นเท่านั้น ตามที่ระบุไว้ใน$PPID,กระบวนการนี้ถูกปฏิเสธโดยสถานีและเป็นลูกโดยตรงของ$PID 1.

หากคุณต้องการเรียกใช้สองสิ่งนี้พร้อมกันและรอพวกเขาคุณสามารถส่งpsทั้งสองของ pids และรอ

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