Bagaimana saya menempatkan proses yang sudah berjalan di bawah nohup?

940

Saya memiliki proses yang sudah berjalan untuk waktu yang lama dan tidak ingin mengakhirinya.

Bagaimana saya meletakkannya di bawah nohup (yaitu, bagaimana saya membuatnya terus berjalan bahkan jika saya menutup terminal?)

flybywire
sumber
29
Untuk siapa pun yang menghadapi masalah yang sama: Ingat, bahwa bahkan jika Anda mengetik yourExecutable &dan output terus muncul di layar dan Ctrl+Ctampaknya tidak menghentikan apa pun, ketik saja secara membabi buta disown;dan tekan Enterbahkan jika layar bergulir dengan output dan Anda tidak dapat melihat apa Anda sedang mengetik. Proses ini akan ditolak dan Anda akan dapat menutup terminal tanpa proses sekarat.
Nav

Jawaban:

1367

Menggunakan Kontrol Pekerjaan bash untuk mengirim proses ke latar belakang:

  1. Ctrl+ Zuntuk menghentikan (menghentikan sementara) program dan kembali ke shell.
  2. bg untuk menjalankannya di latar belakang.
  3. disown -h [job-spec]di mana [job-spec] adalah nomor pekerjaan (seperti %1untuk pekerjaan pertama yang berjalan; cari nomor Anda dengan jobsperintah) sehingga pekerjaan tersebut tidak terbunuh saat terminal ditutup.
Node
sumber
38
Karena pertanyaannya adalah bagaimana "meletakkannya di bawah nohup", disown -hmungkin adalah jawaban yang lebih tepat: "membuat disown bersikap lebih seperti nohup (yaitu pekerjaan akan tetap berada di pohon proses shell Anda saat ini sampai Anda keluar dari shell Anda) Ini memungkinkan Anda untuk melihat semua pekerjaan yang dimulai shell ini. " (dari [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
Dr. Jan-Philip Gehrcke
8
Bagaimana saya memulihkan pekerjaan nanti? Saya bisa melihatnya berjalan menggunakan ps -e.
Paulo Casaretto
26
Anda tidak dapat melihat output dari suatu pekerjaan setelah a disown, disown menjadikan sebuah proses daemon, yang berarti input / output standar dialihkan ke / dev / null. Jadi, jika Anda berencana untuk menolak suatu pekerjaan, lebih baik memulainya dengan masuk ke file, misalnyamy_job_command | tee my_job.log
rustyx
8
apakah mungkin untuk melakukan sesuatu seperti 'my_job_command | tee my_job.log ' setelah perintah sudah berjalan?
arod
23
disownlepaskan semua pipa dari proses. Untuk memasang kembali pipa, gunakan gdbseperti yang dijelaskan di utas ini . Lebih khusus lagi, posting ini .
mbrownnyc
185

Misalkan karena beberapa alasan Ctrl+ Zjuga tidak berfungsi, pergi ke terminal lain, cari id proses (menggunakan ps) dan jalankan:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPakan menunda proses dan SIGCONTakan melanjutkan proses, di latar belakang. Jadi sekarang, menutup kedua terminal Anda tidak akan menghentikan proses Anda.

Pungs
sumber
10
Ya, itu masalah OS, kill tidak bekerja dengan Cygwin di Windows.
Pungs
6
Juga sangat berguna jika pekerjaan dimulai dari sesi ssh lain.
Amir Ali Akbari
5
Ingatlah untuk melakukan disown %1terminal pertama sebelum menutupnya.
fred
1
Ini berguna karena saya memulai antarmuka grafis dengan konsol (dalam kasus saya, saya mulai dari konsole kwinsetelah crash tanpa memikirkan konsekuensinya). Jadi, jika saya berhenti kwin, semuanya akan membeku dan saya tidak memiliki kemungkinan untuk lari bg!
Michele
@ Fred Saya tidak melakukan ini dan sepertinya terus berjalan. Kemungkinan atau apakah saya menekan PID yang salah?
Tidak ada yang
91

Perintah untuk memisahkan pekerjaan yang sedang berjalan dari shell (= membuatnya nohup) adalah disowndan perintah dasar shell.

Dari bash-manpage (man bash):

menolak [-ar] [-h] [jobspec ...]

Tanpa opsi, setiap jobspec dihapus dari tabel pekerjaan aktif. Jika opsi -h diberikan, setiap jobspec tidak dihapus dari tabel, tetapi ditandai sehingga SIGHUP tidak dikirim ke pekerjaan jika shell menerima SIGHUP. Jika tidak ada jobspec, dan opsi -a atau -r tidak disediakan, pekerjaan saat ini digunakan. Jika tidak ada jobspec yang disediakan, opsi -a berarti menghapus atau menandai semua pekerjaan; opsi -r tanpa argumen jobspec membatasi operasi untuk menjalankan pekerjaan. Nilai pengembaliannya adalah 0 kecuali jika suatu jobspec tidak menentukan pekerjaan yang valid.

Itu artinya, itu sederhana

disown -a

akan menghapus semua pekerjaan dari tabel pekerjaan dan membuatnya tidak ada

serioys sam
sumber
9
disown -amenghapus semua pekerjaan. Sederhana disownhanya menghilangkan pekerjaan saat ini. Seperti halaman manual dalam jawaban mengatakan.
Rune Schjellerup Philosof
73

Ini adalah jawaban yang bagus di atas, saya hanya ingin menambahkan klarifikasi:

Anda tidak dapat disownmelakukan pid atau proses, Anda disownpekerjaan, dan itu adalah perbedaan penting.

Pekerjaan adalah sesuatu yang merupakan gagasan tentang proses yang melekat pada shell, oleh karena itu Anda harus membuang pekerjaan ke latar belakang (tidak menangguhkannya) dan kemudian menolaknya.

Isu:

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

Lihat http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ untuk diskusi lebih rinci tentang Kontrol Pekerjaan Unix.

Q Boiler
sumber
48

Sayangnya disownkhusus untuk bash dan tidak tersedia di semua shell.

Rasa Unix tertentu (misalnya AIX dan Solaris) memiliki opsi pada nohupperintah itu sendiri yang dapat diterapkan untuk proses yang berjalan:

nohup -p pid

Lihat http://en.wikipedia.org/wiki/Nohup

Lembah
sumber
Hanya untuk AIXdan Solaris. "Versi nohup AIX dan Solaris memiliki opsi -p yang memodifikasi proses yang berjalan untuk mengabaikan sinyal SIGHUP masa depan. Tidak seperti bawaan yang dijelaskan di atas yang dibangun oleh bash, nohup -p menerima ID proses.". Sumber
AlikElzin-kilaka
27

Jawaban Node benar-benar hebat, tetapi tetap membuka pertanyaan bagaimana stdout dan stderr diarahkan. Saya menemukan solusi di Unix & Linux , tetapi juga tidak lengkap. Saya ingin menggabungkan dua solusi ini. Ini dia:

Untuk pengujian saya, saya membuat skrip bash kecil yang disebut loop.sh, yang mencetak pid itu sendiri dengan tidur sebentar dalam loop tak terbatas.

$./loop.sh

Sekarang dapatkan PID dari proses ini entah bagaimana. Biasanya ps -C loop.shcukup baik, tetapi dicetak dalam kasus saya.

Sekarang kita dapat beralih ke terminal lain (atau tekan ^ Z dan di terminal yang sama). Sekarang gdbharus dilampirkan ke proses ini.

$ gdb -p <PID>

Ini menghentikan skrip (jika berjalan). Keadaannya dapat diperiksa oleh ps -f <PID>, di mana STATbidangnya adalah 'T +' (atau dalam kasus ^ Z 'T'), yang artinya (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

Tutup (1) mengembalikan nol jika berhasil.

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

Buka (1) mengembalikan deskriptor file baru jika berhasil.

Terbuka ini sama dengan open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Alih-alih O_RDWR O_WRONLYbisa diterapkan, tetapi /usr/sbin/lsofmengatakan 'u' untuk semua penangan file std * ( FDkolom), yaitu O_RDWR.

Saya memeriksa nilai di file header /usr/include/bits/fcntl.h.

File output dapat dibuka dengan O_APPEND, seperti yang nohupakan dilakukan, tetapi ini tidak disarankan oleh man open(2), karena kemungkinan masalah NFS.

Jika kita mendapatkan -1 sebagai nilai kembali, lalu call perror("")mencetak pesan kesalahan. Jika kita membutuhkan errno, gunakan p errnoperintah gdb.

Sekarang kita dapat memeriksa file yang baru diarahkan. /usr/sbin/lsof -p <PID>cetakan:

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

Jika kita mau, kita dapat mengarahkan stderr ke file lain, jika kita ingin menggunakan call close(2)dan call open(...)lagi menggunakan nama file yang berbeda.

Sekarang yang terlampir bashharus dilepaskan dan kita dapat berhenti gdb:

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

Jika skrip dihentikan oleh gdbdari terminal lain itu terus berjalan. Kita dapat beralih kembali ke terminal loop.sh. Sekarang tidak menulis apa pun ke layar, tetapi menjalankan dan menulis ke dalam file. Kita harus meletakkannya di latar belakang. Jadi tekan ^Z.

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

(Sekarang kita berada dalam kondisi yang sama seolah-olah ^Zditekan di awal.)

Sekarang kita dapat memeriksa status pekerjaan:

$ 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

Jadi proses harus berjalan di latar belakang dan terlepas dari terminal. Angka dalam jobsoutput perintah dalam tanda kurung mengidentifikasi pekerjaan di dalam bash. Kita bisa menggunakan bashperintah bawaan berikut yang menerapkan tanda '%' sebelum nomor pekerjaan:

$ 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

Dan sekarang kita bisa berhenti dari bash panggilan. Proses terus berjalan di latar belakang. Jika kita menghentikan PPID-nya menjadi proses 1 (init (1)) dan terminal kontrol menjadi tidak dikenal.

$ 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)

KOMENTAR

Hal-hal gdb dapat secara otomatis membuat file (misalnya loop.gdb) yang berisi perintah dan jalankan gdb -q -x loop.gdb -p <PID>. Loop.gdb saya terlihat seperti ini:

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

Atau seseorang dapat menggunakan liner berikut sebagai gantinya:

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

Saya harap ini adalah deskripsi solusi yang cukup lengkap.

Benar
sumber
Memang sangat informatif, dan kemungkinan akan bekerja dengan baik dalam kasus-kasus sederhana. Tetapi berhati-hatilah, kasus yang lebih kompleks mungkin gagal total. Saya memiliki salah satu dari itu hari ini: Proses saya telah menghasilkan proses lain yang menghasilkan output (mungkin untuk stderr), tetapi tetap terhubung untuk berkomunikasi dengan tuannya. Mengarahkan FD tuan tidak efektif karena anak itu mewarisi stderr, dan menutup anak-anak itu gagal membuat master yang menunggu di ujung pipa yang lain. X- | Bettern tahu proses Anda dengan baik sebelum Anda mencoba ini.
cmaster - mengembalikan monica
@ cmaster Anda dapat memeriksa apakah sebuah pegangan dialihkan menggunakan lsof(nama file menangani adalah pipetidak suka /dev/pts/1) atau dengan ls -l /proc/<PID>/fd/<fd>(ini menunjukkan symlink dari pegangan). Selain itu, subproses masih belum dapat mengalihkan keluaran, yang harus diarahkan ke file.
Benar,
7

Untuk mengirim proses yang sedang berjalan ke nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid , itu tidak berhasil untuk saya

Kemudian saya mencoba perintah berikut dan itu bekerja dengan sangat baik

  1. Jalankan beberapa SOMECOMMAND, katakanlah /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zuntuk menghentikan (menghentikan sementara) program dan kembali ke shell.

  3. bg untuk menjalankannya di latar belakang.

  4. disown -h sehingga proses tidak terbunuh saat terminal ditutup.

  5. Ketik exituntuk keluar dari shell karena sekarang Anda baik untuk pergi karena operasi akan berjalan di latar belakang dalam prosesnya sendiri, sehingga tidak terkait dengan shell.

Proses ini setara dengan berjalan nohup SOMECOMMAND.

minhas23
sumber
3

Pada sistem AIX saya, saya mencoba

nohup -p  processid>

Ini bekerja dengan baik. Itu terus menjalankan proses saya bahkan setelah menutup terminal windows. Kami memiliki ksh sebagai shell default sehingga perintah bgdan disowntidak bekerja.

tamu
sumber
2
  1. ctrl+ z - ini akan menghentikan sementara pekerjaan (tidak akan membatalkan!)
  2. bg - ini akan menempatkan pekerjaan di latar belakang dan kembali dalam proses yang berjalan
  3. disown -a - ini akan memotong semua lampiran dengan pekerjaan (sehingga Anda dapat menutup terminal dan itu akan tetap berjalan)

Langkah-langkah sederhana ini akan memungkinkan Anda untuk menutup terminal sambil menjaga proses tetap berjalan.

Itu tidak akan memakai nohup(berdasarkan pemahaman saya tentang pertanyaan Anda, Anda tidak membutuhkannya di sini).

Alper t. Turker
sumber
Saya pikir perilaku untuk dipungkiri -a adalah memotong keterikatan dengan semua pekerjaan. Namun, itu tidak mematikan pipa stdin / stdout, yang berarti bahwa proses tersebut masih akan mencoba untuk menulis (/ membaca) dari terminal
Kelthar
-2

Ini bekerja untuk saya di Ubuntu linux saat di tcshell.

  1. CtrlZ untuk menghentikannya

  2. bg untuk berjalan di latar belakang

  3. jobs untuk mendapatkan nomor pekerjaannya

  4. nohup %n di mana n adalah nomor pekerjaan

eshaya
sumber
2
Tidak, itu tidak berfungsi:nohup: failed to run command '%1': No such file or directory
Dunatotatos