ฉันจะเริ่มต้นกระบวนการในสถานะที่ถูกระงับภายใต้ Linux ได้อย่างไร


19

ในทางปฏิบัติฉันต้องการกระบวนการที่ทำงานเหมือนกับว่าฉันกดCtrl+Zหลังจากเริ่ม

หวังว่ามันเป็นไปได้ที่จะทำสิ่งนี้โดยใช้เชลล์สคริปต์

(และการรู้ PID ที่เกิดขึ้นจะดีมากดังนั้นฉันจึงสามารถดำเนินการต่อได้ในภายหลัง)

คำตอบ:


7

หลังจากเริ่มต้นกระบวนการคุณสามารถส่ง SIGSTOP เพื่อระงับมัน หากต้องการดำเนินการต่อให้ส่ง SIGCONT ฉันคิดว่าสคริปต์ตัวนี้อาจช่วยคุณได้

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID

มันรันกระบวนการ (คำสั่งส่งเป็นพารามิเตอร์) หยุดชั่วคราวพิมพ์รหัสกระบวนการและรอจนกว่าจะสิ้นสุด


1
ฉันแก้ไขมันเพื่อดำเนินการต่อในตอนท้าย: [Enter] #!/bin/bash [enter] $@ & [enter] PID=$! [enter] kill -STOP $PID [enter] echo "Suspended: $PID, press ENTER to continue it" [enter] read [enter] kill -CONT $PID [enter] wait $PID [enter] [enter]echo
java.is.for.desktop

7
เพื่อให้คุณรู้ว่ากระบวนการย่อยอาจเสร็จสิ้นก่อนที่คุณจะมีโอกาสส่งสัญญาณ STOP
MikeyB

16
อีกวันหนึ่งในการแข่งขัน
ctrl-alt-delor

23

คุณสร้างกระบวนการจากสภาพแวดล้อมใด

หากคุณกำลังทำจากสภาพแวดล้อมเช่นรหัส C คุณสามารถแยก () และจากนั้นในเด็กส่ง SIGSTOP ให้กับตัวเองก่อนที่ exec () ป้องกันการดำเนินการต่อไป

วิธีแก้ปัญหาทั่วไปเพิ่มเติม (น่าจะดีที่สุด) คือการสร้างส่วนที่ทำเช่นนั้น ดังนั้นโปรแกรม stub จะ:

  • รับอาร์กิวเมนต์ที่ประกอบด้วยชื่อและอาร์กิวเมนต์ของโปรแกรมจริง
  • ส่ง SIGSTOP ให้ตัวเอง
  • exec () โปรแกรมจริงที่มีข้อโต้แย้งที่เหมาะสม

สิ่งนี้จะช่วยให้แน่ใจว่าคุณหลีกเลี่ยงเงื่อนไขการแข่งขันใด ๆ ที่เกี่ยวข้องกับการประมวลผลใหม่ที่ไกลเกินไปก่อนที่คุณจะสามารถส่งสัญญาณได้


ตัวอย่างสำหรับเชลล์:

#!/bin/bash
kill -STOP $$
exec "$@"

และใช้รหัสข้างต้น:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 

การjobs -lแสดง PID แต่ถ้าคุณทำจากเปลือกคุณไม่จำเป็นต้องใช้ PID โดยตรง คุณสามารถทำได้: kill -CONT %1(สมมติว่าคุณมีเพียงงานเดียว)

ทำมากกว่าหนึ่งงานหรือไม่? ทิ้งไว้เป็นแบบฝึกหัดสำหรับผู้อ่าน :)


ฉันหวังว่าจะทำสิ่งนี้จากเชลล์สคริปต์ ...
java.is.for.desktop

เยี่ยมมากเนื่องจากคุณต้องการทำสิ่งนี้จากเชลล์สคริปต์ให้ใช้โปรแกรม stub
MikeyB

20

คำตอบของ MikeyB นั้นถูกต้อง จากคำถามนี้ใน superuser นี่เป็นเวอร์ชั่นที่กระชับกว่านี้:

( kill -SIGSTOP $BASHPID; exec my_command ) &

เพื่อให้เข้าใจสิ่งนี้เราต้องเข้าใจว่ากระบวนการเริ่มต้นในยูนิกซ์ได้อย่างไร: การexecเรียกของระบบจะแทนที่โปรแกรมที่กำลังทำงานอยู่ในปัจจุบันด้วยโปรแกรมใหม่โดยรักษา PID ที่มีอยู่เดิมไว้ ดังนั้นวิธีการสร้างกระบวนการอิสระคือก่อนforkแล้วจึงexecแทนที่โปรแกรมที่กำลังทำงานอยู่ในกระบวนการลูกด้วยโปรแกรมที่ต้องการ

ส่วนผสมของคำสั่งเชลล์นี้คือ:

  1. วงเล็บ(...)เริ่มต้นเชลล์ย่อย: อินสแตนซ์อื่นของ BASH
  2. killคำสั่งส่งสัญญาณ STOP เพื่อกระบวนการนี้ซึ่งทำให้มันเป็นรัฐที่ถูกระงับ
  3. ทันทีที่คุณอนุญาตให้กระบวนการดำเนินการต่อ (โดยส่งCONTสัญญาณ) execคำสั่งจะทำให้กระบวนการแทนที่ตัวเองด้วยโปรแกรมที่คุณต้องการ my_commandเก็บ PID ดั้งเดิมของ sub-shell
  4. คุณสามารถใช้$!ตัวแปรเพื่อรับ PID ของกระบวนการ

2
ฉันชอบอันนี้เพราะมันถูกต้องพื้นฐาน (แค่ที่ฉันต้องใช้-s STOPแทน-SIGSTOP) ยังสงสัย: ทำไมต้องเป็น$BASHPIDแทน$$? (ฉันอาจไม่เข้าใจความแตกต่างจริงๆ)
Hibou57

1
สำหรับ$$vs $BASHPIDฉันตรวจสอบอย่างหลังคือ PID ของ sub-shell ในขณะที่ไม่ใช่แบบเดิม มีปัญหาตลกคือ: การใช้เคล็ดลับในสคริปต์ทุบตีมักล้มเหลวและฉันต้องทำสิ่งนี้: PID=$!; ps -p $PID; kill -s CONT $PID;... มันล้มเหลวถ้าฉันลบps -p $PIDส่วน: กระบวนการดูเหมือนจะหายไป (ฆ่า?) โดยไม่มีข้อผิดพลาดที่ใดก็ได้ . ไม่เป็นไรจากเชลล์แบบโต้ตอบปัญหามาจากสคริปต์เท่านั้น มันลึกลับมากเกินไป
Hibou57

ฉันพยายามใช้วิธีแก้ปัญหานี้เพื่อระบุรายชื่อตัวอธิบายไฟล์ของ my_command ( goo.gl/cNbUE8 ) แต่ตัวให้คำอธิบายยังคงไม่เหมือนกันว่า my_command คืออะไร
rasty.g

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