ฉันจะวางกระบวนการที่กำลังทำงานอยู่ภายใต้ nohup ได้อย่างไร


940

ฉันมีกระบวนการที่ทำงานมาแล้วเป็นเวลานานและไม่ต้องการจบมัน

ฉันจะวางไว้ใต้ nohup ได้อย่างไร (นั่นคือฉันจะทำให้มันทำงานต่อไปได้อย่างไรแม้ว่าฉันจะปิดเครื่อง?)


29
สำหรับทุกคนที่ประสบปัญหาเดียวกัน: โปรดจำไว้ว่าแม้ว่าคุณจะพิมพ์yourExecutable &และเอาท์พุทยังคงปรากฏบนหน้าจอและCtrl+Cดูเหมือนจะไม่หยุดอะไรเลยเพียงแค่พิมพ์สุ่มสี่สุ่มห้าdisown;และกดEnterแม้ว่าหน้าจอจะเลื่อนด้วยเอาท์พุท คุณกำลังพิมพ์ กระบวนการจะถูกปฏิเสธและคุณจะสามารถปิดเครื่องได้โดยไม่ต้องเสียกระบวนการ
Nav

คำตอบ:


1367

การใช้Job Control of bash เพื่อส่งกระบวนการไปยังพื้นหลัง:

  1. Ctrl+ Zเพื่อหยุด (หยุด) โปรแกรมและกลับไปที่เชลล์
  2. bg เพื่อรันในพื้นหลัง
  3. disown -h [job-spec]โดยที่ [job-spec] คือหมายเลขงาน (เช่น%1สำหรับงานแรกที่ทำงานค้นหาเกี่ยวกับหมายเลขของคุณด้วยjobsคำสั่ง) เพื่อให้งานไม่ถูกฆ่าเมื่อปิดเทอร์มินัล

38
เนื่องจากคำถามคือวิธี "วางไว้ใต้ nohup" disown -hอาจเป็นคำตอบที่ถูกต้องมากขึ้น: "ทำให้การปฏิเสธไม่ทำงานเหมือน nohup (เช่นงานจะอยู่ในแผนผังกระบวนการเชลล์ปัจจุบันของคุณจนกว่าคุณจะออกจากเชลล์) สิ่งนี้ช่วยให้คุณเห็น งานทั้งหมดที่เชลล์นี้เริ่ม " (จาก [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/ … )
Dr. Jan-Philip Gehrcke

8
ฉันจะกู้คืนงานในภายหลังได้อย่างไร ฉันเห็นมันทำงานโดยใช้ ps -e
Paulo Casaretto

26
คุณไม่สามารถเห็นผลลัพธ์ของงานหลังจาก a disown, disown ทำให้กระบวนการ daemon ซึ่งหมายความว่าอินพุต / เอาต์พุตมาตรฐานถูกเปลี่ยนเส้นทางไปยัง / dev / null ดังนั้นหากคุณวางแผนที่จะปฏิเสธงานควรเริ่มต้นด้วยการเข้าสู่ไฟล์เช่นmy_job_command | tee my_job.log
rustyx

8
เป็นไปได้ไหมที่จะทำบางสิ่งเช่น 'my_job_command | ที my_job.log ' หลังจากที่คำสั่งทำงานอยู่แล้ว?
Arod

23
disownยกเลิกการเชื่อมโยงท่อใด ๆ ออกจากกระบวนการ หากต้องการติดตั้งท่ออีกครั้งให้ใช้gdbตามที่อธิบายไว้ในชุดข้อความนี้ โดยเฉพาะโพสต์นี้
mbrownnyc

185

สมมติว่าด้วยเหตุผลบางอย่างCtrl+ Zยังไม่ทำงานให้ไปที่เทอร์มินัลอื่นค้นหา id กระบวนการ (โดยใช้ps) และเรียกใช้:

kill -SIGSTOP PID 
kill -SIGCONT PID

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


10
ใช่นั่นเป็นปัญหาของระบบปฏิบัติการ kill ไม่ทำงานกับ Cygwin บน Windows
Pungs

6
มีประโยชน์มากเช่นกันหากงานเริ่มจากเซสชันอื่น ssh
Amir Ali Akbari

5
เพียงจำไว้ว่าให้ทำdisown %1ในเทอร์มินัลแรกก่อนที่จะปิด
fred

1
สิ่งนี้มีประโยชน์ตั้งแต่ฉันเริ่มอินเทอร์เฟซแบบกราฟิกกับคอนโซล (ในกรณีของฉันฉันเริ่มจาก konsole kwinหลังจากเกิดความผิดพลาดโดยไม่คิดถึงผลที่ตามมา) ดังนั้นถ้าฉันหยุด kwin ทุกอย่างจะแข็งและฉันก็ไม่มีทางวิ่งได้bg!
Michele

@ เฟรดฉันไม่ได้ทำสิ่งนี้และดูเหมือนว่าจะยังคงทำงานต่อไป เป็นไปได้หรือฉันกดหมายเลข PID ผิดหรือเปล่า
ไม่มีใคร

91

คำสั่งเพื่อแยกงานที่กำลังรันอยู่จากเชลล์ (= ทำให้ไม่มีงาน) คือ disownและคำสั่งพื้นฐานของเชลล์

จาก bash-manpage (man bash):

ปฏิเสธ [-ar] [-h] [jobspec ... ]

หากไม่มีตัวเลือกงานแต่ละงานจะถูกลบออกจากตารางของงานที่ใช้งานอยู่ หากกำหนดตัวเลือก -h แต่ละงานจะไม่ถูกลบออกจากตาราง แต่ทำเครื่องหมายเพื่อให้ SIGHUP ไม่ได้ถูกส่งไปยังงานหากเชลล์ได้รับ SIGHUP หากไม่มี jobspec และไม่มีการระบุอ็อพชัน -a หรือ -r งานปัจจุบันจะถูกใช้ หากไม่มีการระบุ jobspec ตัวเลือก -a หมายถึงการลบหรือทำเครื่องหมายงานทั้งหมด อ็อพชัน -r โดยไม่มีอาร์กิวเมนต์ jobspec จำกัด การดำเนินการกับการรันงาน ค่าส่งคืนคือ 0 เว้นแต่ jobspec ไม่ได้ระบุงานที่ถูกต้อง

นั่นหมายความว่าง่าย

disown -a

จะลบงานทั้งหมดออกจากตารางงานและทำให้ไม่มีงานทำ


9
disown -aลบงานทั้งหมด ง่ายdisownลบงานปัจจุบันเท่านั้น ในฐานะที่เป็นหน้าคนในคำตอบพูดว่า
Rune Schjellerup Philosof

73

เหล่านี้เป็นคำตอบที่ดีข้างต้นฉันแค่ต้องการเพิ่มความกระจ่าง:

คุณไม่สามารถdisownpid หรือกระบวนการคุณdisownเป็นงานและนั่นคือความแตกต่างที่สำคัญ

งานเป็นสิ่งที่เป็นความคิดของกระบวนการที่แนบมากับเชลล์ดังนั้นคุณต้องโยนงานลงในพื้นหลัง (ไม่ระงับ) และปฏิเสธมัน

ปัญหา:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

ดูhttp://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ สำหรับการสนทนาอย่างละเอียดของ Unix Job Control


48

น่าเสียดายที่disownมีเฉพาะในการทุบตีและไม่สามารถใช้ได้ในทุกกระสุน

รสชาติบางอย่างของ Unix (เช่น AIX และ Solaris) มีตัวเลือกในnohupคำสั่งซึ่งสามารถนำไปใช้กับกระบวนการที่กำลังทำงานอยู่:

nohup -p pid

ดูhttp://en.wikipedia.org/wiki/Nohup


เฉพาะและAIX Solaris"nohup เวอร์ชัน AIX และ Solaris มีตัวเลือก -p ที่ปรับเปลี่ยนกระบวนการที่กำลังทำงานอยู่เพื่อละเว้นสัญญาณ SIGHUP ในอนาคตซึ่งแตกต่างจากตัวสร้าง disin ของ bash ที่อธิบายไว้ข้างต้น nohup -p ยอมรับรหัสกระบวนการ" แหล่งที่มา
AlikElzin-kilaka

27

คำตอบของโหนดนั้นยอดเยี่ยมจริง ๆ แต่เหลือเปิดคำถามว่าจะเปลี่ยน stdout และ stderr ได้อย่างไร ฉันพบวิธีแก้ปัญหาบนUnix & Linuxแต่ก็ยังไม่สมบูรณ์ ฉันต้องการรวมสองวิธีนี้เข้าด้วยกัน นี่มันคือ:

สำหรับการทดสอบของฉันฉันได้สร้างสคริปต์ทุบตีเล็ก ๆ ชื่อว่า loop.sh ซึ่งพิมพ์ pid ของตัวเองด้วยการนอนหลับเป็นนาทีในวงวนไม่สิ้นสุด

$./loop.sh

ตอนนี้รับ PID ของกระบวนการนี้อย่างใด มักจะps -C loop.shจะดีพอ แต่มันถูกพิมพ์ในกรณีของฉัน

ตอนนี้เราสามารถสลับไปยังเทอร์มินัลอื่น (หรือกด ^ Z และในเทอร์มินัลเดียวกัน) ตอนนี้gdbควรแนบกับกระบวนการนี้

$ gdb -p <PID>

สิ่งนี้จะหยุดสคริปต์ (หากทำงาน) สามารถตรวจสอบสถานะได้โดยps -f <PID>ที่STATฟิลด์คือ 'T +' (หรือในกรณีที่ ^ Z 'T') ซึ่งหมายถึง (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

ปิด (1) ส่งคืนศูนย์เมื่อสำเร็จ

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Open (1) ส่งคืน file descriptor ใหม่ถ้าสำเร็จ

open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)เปิดนี้เป็นที่เท่าเทียมกันกับ แทนที่จะO_RDWR O_WRONLYสามารถนำไปใช้ แต่/usr/sbin/lsofพูดว่า 'U' สำหรับ STD ทั้งหมด * ขนย้ายไฟล์ ( FDคอลัมน์) O_RDWRซึ่งเป็น

ฉันตรวจสอบค่าในไฟล์ /usr/include/bits/fcntl.h

ไฟล์เอาต์พุตสามารถเปิดได้O_APPENDเช่นเดียวกับที่nohupทำ แต่ไม่แนะนำโดยman open(2)เนื่องจากปัญหา NFS ที่เป็นไปได้

หากเราได้รับ -1 เป็นค่าตอบแทนแล้วcall perror("")พิมพ์ข้อความผิดพลาด หากเราต้องการ errno ให้ใช้p errnogdb comand

ตอนนี้เราสามารถตรวจสอบไฟล์ที่เปลี่ยนเส้นทางใหม่ /usr/sbin/lsof -p <PID>พิมพ์:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

หากเราต้องการเราสามารถเปลี่ยนเส้นทาง stderr ไปยังไฟล์อื่นหากเราต้องการใช้call close(2)และcall open(...)อีกครั้งโดยใช้ชื่อไฟล์อื่น

ตอนนี้ไฟล์แนบbashจะต้องมีการเปิดตัวและเราสามารถออกจากgdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

หากสคริปต์หยุดทำงานโดยgdbเทอร์มินัลอื่นสคริปต์จะยังคงทำงานต่อไป เราสามารถสลับกลับไปที่เทอร์มินัลของ loop.sh ตอนนี้มันไม่ได้เขียนอะไรไปยังหน้าจอ แต่ทำงานและเขียนลงในไฟล์ เราต้องใส่มันเข้าไปในพื้นหลัง ดังนั้นกด^Zดังนั้นกด

^Z
[1]+  Stopped                 ./loop.sh

(ตอนนี้เราอยู่ในสถานะเดียวกันกับถ้า ^Zถูกกดที่จุดเริ่มต้น)

ตอนนี้เราสามารถตรวจสอบสถานะของงาน:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

ดังนั้นกระบวนการควรทำงานในพื้นหลังและแยกออกจากเทอร์มินัล จำนวนในการออกคำสั่งในวงเล็บระบุภายในงานjobs bashเราสามารถใช้bashคำสั่งบิวด์อินต่อไปนี้ที่ใช้เครื่องหมาย '%' หน้าหมายเลขงาน:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

และตอนนี้เราสามารถออกจากการเรียกทุบตี กระบวนการทำงานต่อเนื่องในพื้นหลัง ถ้าเราออกจาก PPID กลายเป็น 1 (init (1) กระบวนการ) และเทอร์มินัลการควบคุมไม่เป็นที่รู้จัก

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

แสดงความคิดเห็น

สิ่ง gdb สามารถ automatized สร้างไฟล์ (เช่น loop.gdb) gdb -q -x loop.gdb -p <PID>ที่มีคำสั่งและเรียกใช้ loop.gdb ของฉันมีลักษณะเช่นนี้:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

หรือหนึ่งสามารถใช้หนึ่งซับต่อไปนี้แทน:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

ฉันหวังว่านี่เป็นคำอธิบายที่สมบูรณ์ของวิธีแก้ปัญหา


ข้อมูลมากแน่นอนและมีแนวโน้มที่จะทำงานได้ดีในกรณีง่าย ๆ แต่ควรได้รับการเตือนกรณีที่ซับซ้อนมากขึ้นอาจล้มเหลวอย่างน่าสังเวช ฉันมีหนึ่งในวันนี้: กระบวนการของฉันทำให้เกิดกระบวนการอื่นที่เอาท์พุท (น่าจะเป็น stderr) แต่มี stdout เชื่อมต่อสำหรับการสื่อสารกับเจ้านาย การเปลี่ยนทิศทางเจ้านาย FDs นั้นไม่มีผลเพราะเด็กได้รับ stderr ที่สืบทอดมาและการปิด childs stdout ล้มเหลวเจ้านายที่รออยู่ที่ปลายอีกด้านของท่อ แกน X | Bettern รู้ว่ากระบวนการของคุณดีก่อนที่คุณจะลอง
cmaster - คืนสถานะโมนิกา

@cmaster คุณสามารถตรวจสอบว่าหมายเลขอ้างอิงถูกเปลี่ยนเส้นทางโดยใช้lsof(ชื่อของตัวจัดการไฟล์นั้นpipeไม่เหมือน/dev/pts/1) หรือโดยls -l /proc/<PID>/fd/<fd>(นี่จะแสดง symlink ของหมายเลขอ้างอิง) ด้วยกระบวนการย่อยยังคงไม่สามารถเปลี่ยนเส้นทางผลลัพธ์ซึ่งควรเปลี่ยนเส้นทางไปยังไฟล์
TrueY

7

ในการส่งกระบวนการทำงานไปที่ nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid มันไม่ได้ผลสำหรับฉัน

จากนั้นฉันลองคำสั่งต่อไปนี้และมันก็ใช้ได้ดีมาก

  1. เรียก somecommand /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1บางพูด

  2. Ctrl+ Zเพื่อหยุด (หยุด) โปรแกรมและกลับไปที่เชลล์

  3. bg เพื่อรันในพื้นหลัง

  4. disown -h เพื่อไม่ให้กระบวนการถูกทำลายเมื่อเทอร์มินัลปิด

  5. พิมพ์exitเพื่อออกจากเชลล์เพราะตอนนี้คุณทำได้ดีเพราะการดำเนินการจะทำงานในพื้นหลังในกระบวนการของตัวเองดังนั้นจึงไม่ได้เชื่อมโยงกับเชลล์

nohup SOMECOMMANDกระบวนการนี้เป็นเทียบเท่าของการทำงาน


3

บนระบบ AIX ของฉันฉันพยายามแล้ว

nohup -p  processid>

มันใช้งานได้ดี มันยังคงเรียกใช้กระบวนการของฉันแม้หลังจากปิดหน้าต่างเทอร์มินัล เรามี ksh เป็นเชลล์เริ่มต้นดังนั้นคำสั่งbgและdisownไม่ทำงาน


2
  1. ctrl+ z - สิ่งนี้จะหยุดงานชั่วคราว (จะไม่ยกเลิก!)
  2. bg - สิ่งนี้จะทำให้งานอยู่ในพื้นหลังและกลับมาในกระบวนการทำงาน
  3. disown -a - สิ่งนี้จะตัดสิ่งที่แนบมาทั้งหมดกับงาน (เพื่อให้คุณสามารถปิดเครื่องและมันจะยังคงทำงาน)

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

มันจะไม่ใส่nohup(ขึ้นอยู่กับความเข้าใจในคำถามของคุณคุณไม่ต้องการที่นี่)


ฉันคิดว่าพฤติกรรมของการปฏิเสธ - คือการตัดสิ่งที่แนบมากับงานทั้งหมด อย่างไรก็ตามจะไม่ปิดการทำงานของ stdin / stdout pipelines ซึ่งหมายความว่ากระบวนการจะยังคงพยายามเขียน (/ อ่าน) จากเทอร์มินัล
Kelthar

-2

สิ่งนี้ใช้ได้กับฉันบน Ubuntu Linux ในขณะที่อยู่ใน tcshell

  1. CtrlZ เพื่อหยุดชั่วคราว

  2. bg เพื่อทำงานในพื้นหลัง

  3. jobs เพื่อรับหมายเลขงาน

  4. nohup %n โดยที่ n คือหมายเลขงาน


2
ไม่มันไม่ทำงาน:nohup: failed to run command '%1': No such file or directory
Dunatotatos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.