Saya menggunakan `&`: mengapa proses tidak berjalan di latar belakang?

24

Saya tahu bahwa saya dapat menambahkan &perintah untuk menjalankan proses di latar belakang.

Saya SSH'ing ke kotak Ubuntu 12.04 dan menjalankan program python dengan $python program.py &- tetapi ketika saya pergi untuk menutup jendela terminal saya mendapat pesan yang mengatakan bahwa menutup terminal akan mematikan proses yang sedang berjalan.

Kenapa ini? Saya menggunakan ampersand untuk menjalankan proses di latar belakang. Bagaimana saya bisa menjalankannya terlepas dari apakah saya menggunakan SSH?

bernie2436
sumber
Gandakan unix.stackexchange.com/q/4004/69080
Joshua Huber
apt-get install screen, man screen
captcha

Jawaban:

51

Ketika Anda menutup jendela terminal, emulator terminal mengirimkan SIGHUP ke proses yang sedang berjalan, shell Anda. Shell Anda kemudian meneruskan SIGHUP ke semua yang sedang berjalan. Di sistem lokal Anda, ini ssh. Ssh kemudian meneruskan SIGHUP ke apa yang sedang berjalan, shell jarak jauh. Jadi remote shell Anda kemudian mengirimkan SIGHUP ke semua prosesnya, program latar belakang Anda.

Ada 2 cara untuk mengatasi ini.

  1. Lepaskan program latar belakang dari shell Anda.
    1. Gunakan disownperintah setelah latar belakang proses Anda. Ini akan membuat shell melupakannya.
    2. Awali perintah Anda dengan nohup( nohup $python program.py &). Ini mencapai hal yang sama, tetapi dengan menggunakan proses perantara. Pada dasarnya itu mengabaikan sinyal SIGHUP, dan kemudian bercabang & mengeksekusi program Anda yang mewarisi pengaturan, dan kemudian keluar. Karena bercabang, program yang diluncurkan bukan anak dari shell, dan shell tidak tahu tentang hal itu. Dan kecuali itu menginstal penangan sinyal untuk SIGHUP, itu tetap membuat tindakan abaikan.
  2. Gunakan logoutalih-alih menutup jendela terminal. Saat Anda menggunakan logout, ini bukan SIGHUP, sehingga shell tidak akan mengirim SIGHUP ke anak-anaknya.

Selain itu Anda harus memastikan bahwa program Anda tidak menulis ke terminal melalui STDOUT atau STDERR, karena keduanya tidak akan ada lagi setelah terminal keluar. Jika Anda tidak mengarahkan mereka ke sesuatu seperti /dev/null, program akan tetap berjalan, tetapi jika ia mencoba menulis kepada mereka, itu akan mendapatkan SIGPIPE, dan tindakan default SIGPIPE adalah menghentikan proses).

Patrick
sumber
4
Secara teknis, sshmati menyebabkan koneksi turun, koneksi untuk menjatuhkan menyebabkan sshddi ujung yang lain mati. Sshd yang mengendalikan sisi master terminal pseudo yang dijalankan oleh shell jauh, ketika mati, itu adalah hang-up (seperti menarik steker pada terminal nyata), sehingga sistem mengirimkan SIGHUP ke shell jauh.
Stéphane Chazelas
@ StéphaneChazelas Itu satu hal yang belum pernah saya gali. Jika kernel yang melakukannya, bagaimana cara menentukan proses mana yang akan SIGHUP? Jelas tidak SIGHUP segalanya dengan deskriptor file terbuka untuk TTY itu, karena program akan tetap berjalan selama mereka tidak mencoba menggunakannya. Jadi apakah ia memilih program yang saat ini membaca dari STDIN (karena hanya satu yang dapat membaca dari STDIN pada satu waktu)?
Patrick
4
Sudahlah, jawab pertanyaanku sendiri. POSIX IEEE 1003.1 bab 11, Jika pemutusan modem terdeteksi oleh antarmuka terminal untuk terminal pengendali ... sinyal SIGHUP harus dikirim ke proses pengendalian .
Patrick
2
Perhatikan juga bahwa nohupmenghasilkan nohup.outfile dengan output dari program yang Anda mulai dengannya. Mungkin menjengkelkan untuk menghapus file itu setiap kali Anda menggunakan nohup untuk memulai aplikasi dengan cara ini (atau Anda perlu mengarahkan ulang hasilnya ke /dev/null).
Ruslan
1
Alih-alih nohup python program.py &saya merekomendasikan menggunakan setsid python program.pysebagai gantinya, yang segera menolak program.
Hitechcomputergeek
14

Proses sedang berjalan di latar belakang di terminal, tetapi output dari stdout(dan stderr) masih dikirim ke terminal. Untuk menghentikan ini, tambahkan > /dev/null 2>&1sebelum &untuk mengalihkan kedua output ke /dev/null- menambahkan disownjuga memastikan proses tidak terbunuh setelah Anda menutup terminal:

COMMAND > /dev/null 2>&1 & disown

Dalam kasus Anda ini adalah:

python program.py > /dev/null 2>&1 & disown
Wilf
sumber
3

The &memisahkan Operator perintah untuk menjalankan secara paralel, seperti ;memisahkan perintah untuk menjalankan dalam seri. Kedua jenis perintah masih akan berjalan sebagai anak dari proses shell .

Jadi, ketika Anda menutup cangkang yang memulai anak-anak, anak-anak akan ditutup juga.

Apa yang tampaknya Anda inginkan adalah proses daemon , yang secara signifikan lebih rumit karena perlu memisahkan sepenuhnya dari proses induk. Shell biasanya tidak memiliki cara sederhana untuk melakukan itu.

hidung besar
sumber
1

Saat Anda logout, proses latar belakang yang terkait dengan sesi login biasanya juga dimatikan. Jika Anda ingin mereka terputus dari sesi, jalankan dengan nohup.

nohup python program.py &
Barmar
sumber
1

Setelah perintah berakhir dengan ampersand ( &), pada prompt perintah jalankan perintah bg:

bash> python program.py &  
bash> bg  

Ini akan menempatkan perintah "&" ke latar belakang

bash> jobs  

Ini akan mencantumkan pekerjaan yang berjalan di latar belakang

bash> fg 1   

Ini akan membawa Ayub # 1 ke latar depan

Cara lain, (untuk bisa keluar)

bash> at now  
bash> /full/path/python /full/path/program.py  
bash> ^d   `(# That is, Control-D, to run the command, Control-C to cancel)`  

Beberapa baris dapat dikirimkan ke atperintah, sebelum ^ d (Control-D)
lihat man at.

martin
sumber