วิธีหยุดชั่วคราวและนำกระบวนการพื้นหลังมาทำงานเบื้องหน้า


166

ฉันมีกระบวนการที่ทำงานอยู่เบื้องหน้า ฉันหยุดทำงานโดยCtrl+ Zจากนั้นให้ทำงานในพื้นหลังbg <jobid>ต่อ

ฉันสงสัยว่าจะระงับกระบวนการที่ทำงานในพื้นหลังได้อย่างไร

ฉันจะนำกระบวนการพื้นหลังมาสู่เบื้องหน้าได้อย่างไร

แก้ไข:

กระบวนการส่งออกไปยัง stderr ดังนั้นฉันจะออกคำสั่งfg <jobid>ในขณะที่กระบวนการส่งออกไปยังเทอร์มินัลได้อย่างไร


1
คุณยังสามารถพิมพ์คำสั่งในเทอร์มินัลที่พ่นข้อผิดพลาด ข้อความที่พูดกับ STDERR ไม่นับเป็นข้อมูลป้อนเข้าเท่านั้นเฉพาะปุ่มที่คุณส่ง ดูสับสนบนหน้าจอ แต่ใช้งานได้
Caleb

@Caleb: แม้ว่ากระบวนการส่งออกไปยัง stdout ฉันยังคงสามารถพิมพ์fg <jobid>เพื่อให้ทำงานเบื้องหน้าได้?
ทิม

@Tim: ใช่คุณสามารถ
คาเลบ

คำตอบ:


214

ดังที่ทิมกล่าวให้พิมพ์fgเพื่อนำกระบวนการสุดท้ายกลับสู่เบื้องหน้า

หากคุณมีกระบวนการทำงานอยู่เบื้องหลังมากกว่าหนึ่งกระบวนการให้ทำดังนี้

$ jobs
[1]   Stopped                 vim
[2]-  Stopped                 bash
[3]+  Stopped                 vim 23

fg %3เพื่อนำvim 23กระบวนการกลับสู่เบื้องหน้า

หากต้องการระงับกระบวนการที่ทำงานอยู่เบื้องหลังให้ใช้:

kill -STOP %job_id

สัญญาณ SIGSTOP หยุด (หยุด) กระบวนการในหลักทางเดียวกันCtrl+ Zไม่

ตัวอย่าง: kill -STOP %3.

แหล่งที่มา: วิธีการส่งสัญญาณไปยังกระบวนการใน Linux และ Unix และวิธีการจัดการพื้นหลังและพื้นหน้างาน


23
สัญญาณ 19 SIGCONTสำหรับฉัน; ฉันใช้kill -STOPและkill -CONTชอบตั้งค่าการจดจำหมายเลขอยู่แล้ว แต่คุณสามารถตรวจสอบkill -lเพื่อเตือนตัวเองเกี่ยวกับค่าตัวเลข
ไร้ประโยชน์

กระบวนการส่งออกไปยัง stderr ดังนั้นฉันจะออกคำสั่งได้อย่างไรjobและfg <jobid>ในขณะที่กระบวนการส่งออกไปยังเทอร์มินัล
ทิม

1
@Tim เพียงพิมพ์คำสั่งตามปกติ ตราบใดที่งานมีพื้นหลังจะไม่อ่านสิ่งที่คุณพิมพ์ - เชลล์ของคุณคือ สิ่งที่คุณพิมพ์อาจดูแตกสำหรับคุณ แต่เชลล์จะเข้าใจดี
AlexWebr

@AlexWebr: ขอบคุณมันใช้งานได้! (1) งานพื้นหลังไม่ยอมรับอินพุตและเอาต์พุตใด ๆ รวมถึง "Ctrl + Z" ฯลฯ ใช่ไหม? (2) สามารถเรียกใช้งานในพื้นหลังได้โดยตรงหรือไม่ ถ้าใช่เป็นอย่างไร หากไม่มีจะต้องมีการเปลี่ยนแปลงเพื่อให้ทำงานในเบื้องหน้าก่อนที่จะสามารถหยุดทำงานได้หรือไม่
ทิม

2
งานที่ทำงานในพื้นหลังสามารถถูกระงับได้โดยตรงใช่: kill -STOP %job_idตามที่อธิบายไว้
ไม่มีประโยชน์

31

นี่ควรเป็นจริงของเชลล์ใด ๆ ที่มีการควบคุมงานซึ่ง (ส่วนใหญ่) คุณสามารถรับสิทธิ์ยกเว้นว่าจะจัดการกับเชลล์โบราณอย่างแท้จริง มันอยู่ในมาตรฐาน POSIXดังนั้นแม้dashสนับสนุนการควบคุมงาน (เมื่อทำงานแบบโต้ตอบหรือด้วย-m)

อินเตอร์แอคที

  • Ctrl+ zจะระงับโปรแกรมพื้นหน้าในขณะนี้
  • bgจะทำให้พื้นหลังโปรแกรมที่ถูกระงับล่าสุด
    (ใช้bg %2กับหมายเลขงานซึ่งคุณสามารถตรวจสอบได้jobs)
  • fg จะทำงานเบื้องหน้าโปรแกรมที่ถูกระงับล่าสุด

ในzshคุณสามารถเขียนการโยงคีย์เพื่อเรียกใช้fgจากพรอมต์ผ่านทางCtrl+ อื่นz:

_zsh_cli_fg() { fg; }
zle -N _zsh_cli_fg
bindkey '^Z' _zsh_cli_fg

อาจเป็นวิธีที่ฉลาดในการใช้งานโดยปริยายbgเมื่อหยุดทำงานชั่วคราว แต่ดูเหมือนจะไม่ฉลาด อย่างน้อยสำหรับฉันการใช้งานส่วนใหญ่ของฉันCtrl+ zเพราะCtrl+ cไม่สามารถแยกออกได้ ฉันต้องการที่จะทำตามนั้นด้วยเช่นkill %1มากกว่าbgและแน่นอนฉันไม่ต้องการเริ่มต้นที่จะฆ่า! (เหตุผลนี้ยังรวมถึงเหตุผลที่ฉันไม่ใช้การเชื่อมโยงคีย์นี้อีกต่อไป: ถ้าฉันใช้ค้อนทุบกับCtrl+ zเพื่อหยุดกระบวนการสิ่งสุดท้ายที่ฉันต้องการให้ทำคือกลับมาทำงานต่อ!)

ไม่โต้ตอบ

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

คุณยังคงสามารถดำเนินการกับกระบวนการอื่นได้เมื่อคุณทราบรหัสกระบวนการ (PID) แล้ว คุณสามารถรับ PID ด้วยpgrep …หรือps aux |grep …(หรือจากเชลล์เดียวกันjobs -lหรือ$!) และจากนั้นคุณสามารถเรียกใช้:

kill -STOP $PID  # suspend
kill -CONT $PID  # continue (resume)

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

killall -STOP program_name
pkill -STOP program_name
pkill -f -STOP program_name_or_args

CONTสัญญาณไปยังโปรแกรมหยุดCtrl+ z(และไม่ได้bg'D) จะกลับมาความคืบหน้า (ในเบื้องหน้า) เช่นเดียวกับถ้าคุณกำลังจะfgมัน

เรื่องข้อผิดพลาดมาตรฐาน

การแก้ไขคำถามนี้ถามเกี่ยวกับข้อผิดพลาดมาตรฐาน:

กระบวนการส่งออกไปยัง stderr ดังนั้นฉันจะออกคำสั่งfg <jobid>ในขณะที่กระบวนการส่งออกไปยังเทอร์มินัลได้อย่างไร

เว้นแต่งานที่มีปัญหาจะมีส่วนประกอบที่มีพื้นหลัง (หรืองานทั้งหมดมีพื้นหลังหรือผ่านkill -CONT) คุณไม่ควรเห็นผลลัพธ์ในขณะที่ถูกระงับ

หากยังคงส่งออกข้อมูล (ไม่ว่าจะเป็นเอาต์พุตมาตรฐานหรือข้อผิดพลาดมาตรฐาน) จะทำให้เทอร์มินัลของคุณมองไม่เห็นอย่างชัดเจน แต่เอาต์พุตทั้งหมดจะถูกละเว้นเนื่องจากไม่ได้เป็นส่วนหนึ่งของอินพุตของคุณ สิ่งนี้อาจทำให้ยากที่จะรู้ว่าคุณไม่ได้พิมพ์ผิด แต่การพิมพ์ (สุ่มสี่สุ่มห้า) fgEnterควรจะพอเพียง (เว้นแต่คุณจะมีงานหลายงานและงานที่มีปัญหาไม่ใช่งานล่าสุดซึ่งในกรณีนี้คุณจะต้องมีตัวระบุงานแน่นอน )

หากคุณต้องการค้นหาตัวอธิบายงานให้ใช้เทอร์มินัลอื่นเพื่อส่งSTOPสัญญาณผ่านวิธีการที่ไม่โต้ตอบด้านบน สิ่งนี้ควรทำให้จอแสดงผลของคุณว่าง (อาจจะกดEnterสองสามครั้งหรือรันclearหรือCtrl+ L) เพื่อให้คุณสามารถเรียกใช้jobsหา descriptor ของงานจากนั้นเรียกใช้fg %Nตำแหน่งที่Nเป็นหมายเลขนั้น


ปัญหาเดียวของกระบวนการหยุดชั่วคราวและการดำเนินการต่อคือเมื่อคุณทำการเชื่อมต่อกับโปรแกรมอื่น (เช่น RabbitMQ เป็นต้น) การเชื่อมต่อจะหายไปเมื่อคุณกลับมาทำงานต่อ
Nav

@Nav - นั่นเป็นเพราะคุณไม่ได้ทำงานแบบหัวขาด ใน bash และ zsh ฉันเชื่อว่าคุณเพียงแค่ต้องปฏิเสธกระบวนการเบื้องหลัง ฉันชอบที่จะเรียกใช้งานดังกล่าวกับnohupหรือMultiplexer ขั้วเช่นหน้าจอหรือtmux คุณไม่สามารถรับกระบวนการ nohup (เช่นเดียวกับที่คุณไม่สามารถดำเนินการกระบวนการพื้นหลังจากการเชื่อมต่อที่แยกต่างหาก) แต่คุณสามารถเชื่อมต่อกับมัลติเพล็กเซอร์
Adam Katz

มันเป็นกระบวนการพื้นหลัง ฉันปิดเทอร์มินัลแล้วล็อกอินเข้าสู่เซิร์ฟเวอร์จากเทอร์มินัลอื่น
Nav

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

ฉันเชื่อว่าถ้าคุณส่งCONTสัญญาณไปยังกระบวนการ (งาน / ไปป์ไลน์) หยุดทำงานด้วย Ctrl + Z มันจะกลับมาทำงานในพื้นหลังแม้ว่าคุณจะไม่ได้bgทำก็ตาม
G-Man

10

พิมพ์fgเพื่อนำมาไว้ด้านหน้า


ขอบคุณ! กระบวนการส่งออกไปยัง stderr ดังนั้นฉันจะออกคำสั่งfg <jobid>ในขณะที่กระบวนการส่งออกไปยังเทอร์มินัลได้อย่างไร
ทิม

1
  1. รายการงานด้วยjobsคำสั่ง
  2. นำงานเป้าหมายของคุณไปสู่เบื้องหน้าด้วยfg; เช่น: fg %4
  3. กดCTRL Zเพื่อระงับ
  4. ในการเริ่มต้นทำงานในพื้นหลังให้ใช้ bg; เช่น:bg %4

0

การสิ้นสุดกระบวนการสามารถทำได้หลายวิธี บ่อยครั้งที่จากคำสั่งคอนโซลการส่งการCtrlcกดแป้น (อักขระขัดจังหวะเริ่มต้น) จะออกจากคำสั่ง สิ่งนี้จะทำงานเมื่อกระบวนการทำงานในโหมดเบื้องหน้า

หากโปรเซสกำลังทำงานในโหมดแบ็คกราวน์ดังนั้นอันดับแรกคุณจะต้องได้รับ Job ID โดยใช้psคำสั่งและหลังจากนั้นคุณสามารถใช้คำสั่ง kill เพื่อฆ่าโปรเซสดังนี้:

$ps -f
UID      PID  PPID C STIME    TTY   TIME CMD
amrood   6738 3662 0 10:23:03 pts/6 0:00 first_one
amrood   6739 3662 0 10:22:54 pts/6 0:00 second_one
amrood   3662 3657 0 08:10:53 pts/6 0:00 -ksh
amrood   6892 3662 4 10:51:50 pts/6 0:00 ps -f
$kill 6738
Terminated

ที่นี่killคำสั่งจะยุติfirst_oneกระบวนการ หากกระบวนการละเว้นkillคำสั่งปกติคุณสามารถใช้kill -9ตามด้วย ID กระบวนการดังต่อไปนี้:

$kill -9 6738
Terminated

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