(bash) สคริปต์ A รอสคริปต์ B แต่ไม่ใช่กระบวนการลูก


9

ดังนั้นฉันจึงมี scriptA ซึ่ง:

ssh server1 -- scriptB &
ssh server2 -- scriptB &
ssh server3 -- scriptB &
wait
otherstuffhappens

ScriptB ทำ:

rsync -av /important/stuff/. remoteserver:/remote/dir/.
rsync -av /not/so/important/stuff/. remoteserver:/remote/dir/. &
exit

ผลลัพธ์ที่ฉันต้องการคือ scriptA จะรอให้อินสแตนซ์ทั้งหมดของ scriptB เสร็จสิ้นก่อนที่จะดำเนินการต่อไปซึ่งมันทำอยู่ในขณะนี้ ไฟล์เหล่านี้เป็นไฟล์ขนาดใหญ่ที่ฉันไม่ต้องการรอ

ฉันได้อ่านความแตกต่างระหว่าง nohup, บอกเลิกและ &และลองชุดค่าผสมที่แตกต่างกัน แต่ฉันไม่ได้รับผลลัพธ์ที่ต้องการ

ณ จุดนี้ฉันค่อนข้างนิ่งงัน ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม!

คำตอบ:


15

ปัญหาตรงนี้คือการsshdรอคอยการสิ้นสุดไฟล์บนไพพ์ที่กำลังอ่าน stdout ของคำสั่ง (ไม่ใช่ stderr one ด้วยเหตุผลบางประการอย่างน้อยกับเวอร์ชั่นที่ฉันกำลังทดสอบ) และงานพื้นหลังสืบทอด fd ไปยังไพพ์นั้น

ดังนั้นเพื่อหลีกเลี่ยงปัญหานี้ให้เปลี่ยนเส้นทางเอาต์พุตของrsyncคำสั่งพื้นหลังนั้นไปยังไฟล์บางไฟล์หรือ/dev/nullถ้าคุณไม่สนใจมัน คุณควรเปลี่ยนเส้นทาง stderr เพราะแม้ว่า sshd จะไม่รอคอยไปป์ที่เกี่ยวข้องหลังจากsshdออกจากไปป์จะเสียดังนั้นrsyncจะถูกฆ่าหากพยายามเขียน stderr

ดังนั้น:

rsync ... > /dev/null 2>&1 &

เปรียบเทียบ:

$ time ssh localhost 'sleep 2 &'
ssh localhost 'sleep 2 &'  0.05s user 0.00s system 2% cpu 2.365 total
$ time ssh localhost 'sleep 2 > /dev/null &'
ssh localhost 'sleep 2 > /dev/null &'  0.04s user 0.00s system 12% cpu 0.349 total

และ:

$ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null &'; sleep 2; cat out
141  # ls by killed with SIGPIPE upon writing the error message
$ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null 2>&1 &'; sleep 2; cat out
2    # ls exited normally after writing the error on /dev/null instead
     # of a broken pipe

4

เขียนสคริปต์ซึ่งเป็นแม่ของทั้งสองแล้วคุณสามารถควบคุมทั้ง อีกวิธีหนึ่งคือการสร้างช่องทางสื่อสารระหว่างสองช่องทาง

หากต้องการละเว้นงานพื้นหลังบางอย่างโดยเฉพาะคุณสามารถจับภาพ PID ( $!เป็นงานที่มีพื้นหลังล่าสุด PID) และwait $pidรอให้งานนั้นเสร็จสมบูรณ์เท่านั้น


3

การ-fตั้งค่าสถานะเพื่อsshแก้ไขปัญหา ทดสอบเมื่อ:

#!/bin/sh -e
echo $$_script__begin
( echo sleeping; sleep 2; echo slept )&
echo $$_script__end

เมื่อฉันใช้มันssh localhost ./scriptก็จะรอจนกว่าจะsleptปรากฏขึ้น ด้วย-fแฟล็กจะออกecho $$_script__endและsleptแสดงในภายหลังในพื้นหลังหลังจากsshคำสั่งส่งคืน


2

ปัญหานี้เป็นปัญหาที่รู้จักกันของเซิร์ฟเวอร์ OpenSSH, ที่อธิบายและพูดคุยกันในต้นน้ำBugzilla # ในข้อผิดพลาดมีการเสนอวิธีแก้ไขปัญหาต่าง ๆ ทั้งในด้าน OpenSSH แต่สำหรับสคริปต์

หากคุณต้องการที่จะรอสำหรับการส่งออกของสคริปที่คุณควรเพิ่มwaitก่อนexitของscriptBเกินไป

หากคุณไม่สนใจเกี่ยวกับผลลัพธ์ให้ใช้การผันแปรของnohupและการเปลี่ยนเส้นทาง IO ไป/dev/nullซึ่งจะแก้ไขปัญหาแบบเดียวกัน


1

คุณสามารถลองสิ่งนี้ $!เป็นตัวแปรเชลล์เริ่มต้นที่มี ID กระบวนการของไปป์ไลน์พื้นหลัง / กระบวนการที่ดำเนินการล่าสุด

command1 &
lpid1=$!

command2 &
lpid2=$!

command3 &
lpid=$!

wait $lpid1  # waits for only the process with PID lpid1  to complete. 

คุณต้องใช้สิ่งนี้ตามสคริปต์ของคุณโดยใช้exportตัวแปร ฯลฯ


1

B เพียงแค่ต้องรอให้กระบวนการพื้นหลังเป็นของตัวเอง:

rsync -av /important/stuff/. remoteserver:/remote/dir/.
rsync -av /not/so/important/stuff/. remoteserver:/remote/dir/. &
wait
exit

ณ จุดนั้นคุณอาจไม่ได้เรียกใช้ rsync ที่สองในพื้นหลังและหลีกเลี่ยงการใช้waitทั้งหมด แม้ว่าฉันคาดเดาสิ่งที่ OP หมายถึงการทำคือใช้ทั้งrsyncกระบวนการในแบบคู่ขนานซึ่งจะหมายถึง backgrounding พวกเขาทั้งสอง (มี&) waitแล้วใช้ ไม่ว่าในกรณีใดฉันยอมรับว่านี่เป็นวิธีที่ตรงไปตรงมาที่สุดในการแก้ไขปัญหาและเป็นวิธีที่ฉันเลือกจากข้อมูลในคำถาม
David Z
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.