Bagaimana cara memulai proses dalam status ditangguhkan di Linux?

19

Secara praktis, saya membutuhkan proses yang berperilaku, seolah-olah saya telah menekan Ctrl+Ztepat setelah itu dimulai.

Semoga bisa melakukan hal seperti itu menggunakan skrip shell.

(Juga, mengetahui PID yang dihasilkan akan bagus, jadi saya bisa melanjutkan proses setelah itu.)

java.is.for.desktop
sumber

Jawaban:

7

Setelah memulai suatu proses, Anda dapat mengirimkannya SIGSTOP untuk menangguhkannya. Untuk melanjutkannya, kirim SIGCONT. Saya pikir skrip kecil ini dapat membantu Anda

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

Ini menjalankan proses (perintah kirim sebagai parameter), menangguhkannya, mencetak proses id dan menunggu sampai berakhir.

berseri-seri
sumber
1
Saya memodifikasinya untuk melanjutkan di akhir: [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]echo
java.is.for.desktop
7
Asal tahu saja, subproses mungkin selesai bahkan sebelum Anda mendapatkan kesempatan untuk mengirim sinyal STOP ke sana.
MikeyB
16
Lain hari di balapan.
ctrl-alt-delor
23

Dari lingkungan mana Anda membuat proses?

Jika Anda melakukannya dari lingkungan seperti kode C, Anda dapat melakukan fork () dan kemudian pada child, mengirim SIGSTOP ke diri Anda sendiri sebelum exec (), mencegah eksekusi lebih lanjut.

Solusi yang lebih umum (mungkin yang terbaik) adalah dengan membuat rintisan. Jadi program rintisan akan:

  • Ambil argumen yang terdiri dari nama dan argumen program sebenarnya
  • mengirim SIGSTOP ke dirinya sendiri
  • exec () program nyata dengan argumen yang sesuai

Ini akan memastikan bahwa Anda menghindari segala jenis kondisi balapan yang berkaitan dengan pemrosesan baru terlalu jauh sebelum Anda dapat mengirim sinyal ke sana.


Contoh untuk shell:

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

Dan menggunakan kodez di atas:

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:~$ 

The jobs -lmenunjukkan PID. Tetapi jika Anda melakukannya dari shell Anda tidak perlu PID secara langsung. Anda cukup melakukan: kill -CONT %1(dengan asumsi Anda hanya memiliki satu pekerjaan).

Melakukannya dengan lebih dari satu pekerjaan? Ditinggalkan sebagai latihan untuk pembaca :)

MikeyB
sumber
Saya berharap untuk melakukan ini dari skrip shell ...
java.is.for.desktop
Hebat, jadi karena Anda ingin melakukan ini dari skrip shell, gunakan program rintisan.
MikeyB
20

Jawaban MikeyB benar. Dari pertanyaan tentang superuser ini, inilah versi yang lebih ringkas:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Untuk memahami ini, kita perlu memahami bagaimana proses dimulai pada unix: execpanggilan sistem menggantikan program yang sedang berjalan dengan yang baru , menjaga PID yang ada. Jadi cara proses independen dibuat adalah untuk pertama fork, dan kemudian exec, mengganti program yang sedang berjalan dalam proses anak dengan program yang diinginkan.

Bahan dari perintah shell ini adalah:

  1. Tanda kurung (...)memulai sub-shell: contoh lain dari BASH.
  2. The killperintah mengirimkan sinyal STOP untuk proses ini, yang menempatkan ke negara ditangguhkan.
  3. Segera setelah Anda mengizinkan proses untuk melanjutkan (dengan mengirimkannya CONTsinyal), execperintah menyebabkannya untuk mengganti sendiri dengan program yang Anda inginkan. my_commandmenyimpan PID asli dari sub-shell.
  4. Anda bisa menggunakan $!variabel untuk mendapatkan PID dari proses.
nibot
sumber
2
Saya suka yang ini, karena secara fundamental benar (hanya saja saya harus menggunakan -s STOPbukan -SIGSTOP). Masih bertanya-tanya: mengapa harus $BASHPIDbukannya $$? (Saya mungkin tidak benar-benar mengerti perbedaannya).
Hibou57
1
Untuk $$vs $BASHPID, saya periksa yang terakhir adalah PID dari sub-shell, sementara bukan yang pertama. Ada masalah lucu: menerapkan tip dalam skrip bash, paling sering gagal, dan saya harus melakukan sesuatu seperti ini: PID=$!; ps -p $PID; kill -s CONT $PID;... gagal jika saya menghapus ps -p $PIDbagian: prosesnya tampaknya menghilang (terbunuh?) Tanpa pesan kesalahan di mana pun . Tidak apa-apa dari shell interaktif, masalahnya hanya dari skrip. Itu terlalu misterius.
Hibou57
Saya mencoba menggunakan solusi ini untuk daftar deskriptor file dari my_command. ( goo.gl/cNbUE8 ) tetapi deskriptornya tetap sama, tidak ada apa-apa dengan perintah my_ .
rasty.g
Untuk opsi untuk mengganti $BASHPIDshell selain bash, lihat di sini
Jakob