Saya ingin memulai proses (mis. Perintah saya) dan mendapatkan pidnya (untuk memungkinkan untuk membunuhnya nanti).
Saya mencoba ps dan memfilter berdasarkan nama, tetapi saya tidak dapat membedakan proses dengan nama
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Karena proses nama tidak unik.
Saya dapat menjalankan proses dengan:
myCommand &
Saya menemukan bahwa saya bisa mendapatkan PID ini dengan:
echo $!
Apakah ada solusi yang lebih sederhana?
Saya akan senang mengeksekusi perintah saya dan mendapatkan PID sebagai hasil dari satu perintah baris.
myprogram
akan luar biasa&
sebagai baris sebelumnya, jika tidak, gema pada dasarnya kembali kosong.command & echo $!
membekukan eksekusi pada langkah ini :(Bungkus perintah dalam skrip kecil
sumber
Anda dapat menggunakan
sh -c
danexec
untuk mendapatkan PID perintah bahkan sebelum dijalankan.Untuk memulai
myCommand
, sehingga PID-nya dicetak sebelum mulai dijalankan, Anda dapat menggunakan:Bagaimana itu bekerja:
Ini memulai shell baru, mencetak PID dari shell itu, dan kemudian menggunakan
exec
builtin untuk mengganti shell dengan perintah Anda, memastikan ia memiliki PID yang sama. Ketika shell Anda menjalankan perintah denganexec
builtin, shell Anda sebenarnya menjadi perintah itu , daripada perilaku yang lebih umum dari forking salinan baru itu sendiri, yang memiliki PID sendiri yang terpisah dan yang kemudian menjadi perintah.Saya menemukan ini jauh lebih sederhana daripada alternatif yang melibatkan eksekusi asinkron (dengan
&
), kontrol pekerjaan, atau pencarian denganps
. Pendekatan-pendekatan itu baik-baik saja, tetapi kecuali jika Anda memiliki alasan khusus untuk menggunakannya - misalnya, mungkin perintah sudah berjalan, dalam hal mencari PID atau menggunakan kontrol pekerjaan akan masuk akal - saya sarankan mempertimbangkan cara ini terlebih dahulu. (Dan saya pasti tidak akan mempertimbangkan untuk menulis naskah yang rumit atau program lain untuk mencapai ini).Jawaban ini termasuk contoh dari teknik ini.
Sebagian dari perintah itu kadang-kadang bisa dihilangkan, tetapi tidak biasanya.
Bahkan jika shell yang Anda gunakan adalah gaya Bourne dan karenanya mendukung
exec
builtin dengan semantik ini, Anda biasanya tidak boleh mencoba untuk menghindari menggunakansh -c
(atau setara) untuk membuat proses shell baru yang terpisah untuk tujuan ini, karena:myCommand
, tidak ada shell yang menunggu untuk menjalankan perintah berikutnya.sh -c 'echo $$; exec myCommand; foo
tidak akan dapat mencoba menjalankanfoo
setelah mengganti sendiri denganmyCommand
. Kecuali Anda menulis skrip yang menjalankan ini sebagai perintah terakhir, Anda tidak bisa hanya menggunakanecho $$; exec myCommand
di shell di mana Anda menjalankan perintah lain.(echo $$; exec myCommand)
mungkin secara sintaksis lebih bagus daripadash -c 'echo $$; exec myCommand'
, tetapi ketika Anda menjalankan$$
di dalam(
)
, itu memberikan PID dari shell induk, bukan dari subkulit itu sendiri. Tapi itu PID subkulit yang akan menjadi PID dari perintah baru. Beberapa shell menyediakan mekanisme non-portabel mereka sendiri untuk menemukan PID subkulit, yang dapat Anda gunakan untuk ini. Secara khusus, dalam Bash 4 ,(echo $BASHPID; exec myCommand)
berhasil.Akhirnya, perhatikan bahwa beberapa shell akan melakukan optimasi di mana mereka menjalankan perintah seolah-olah oleh
exec
(yaitu, mereka melupakan forking terlebih dahulu) ketika diketahui bahwa shell tidak perlu melakukan apa-apa sesudahnya. Beberapa shell mencoba melakukan ini kapan saja itu adalah perintah terakhir untuk dijalankan, sementara yang lain hanya akan melakukannya ketika tidak ada perintah lain sebelum atau setelah perintah, dan yang lain tidak akan melakukannya sama sekali. Efeknya adalah bahwa jika Anda lupa untuk menulisexec
dan hanya menggunakansh -c 'echo $$; myCommand'
maka itu kadang - kadang akan memberi Anda PID yang tepat pada beberapa sistem dengan beberapa shell. Saya sarankan agar tidak mengandalkan perilaku seperti itu , dan alih-alih selalu termasukexec
saat itulah yang Anda butuhkan.sumber
myCommand
, saya perlu mengatur sejumlah variabel lingkungan di skrip bash saya. Apakah ini akan terbawa ke lingkungan di manaexec
perintah dijalankan?exec
perintah. Namun, pendekatan ini tidak berfungsi ketikamyCommand
memulai proses lain, yang mana Anda perlu bekerja dengannya; ketika saya mengeluarkan dikill -INT <pid>
manapid
diperoleh dengan cara ini, sinyal tidak mencapai sub-proses yang dimulai olehmyCommand
, sedangkan jika saya berjalanmyCommand
di sesi saat ini dan Ctrl + C, sinyal menyebar dengan benar.sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
Saya tidak tahu solusi yang lebih sederhana, tetapi tidak menggunakan $! cukup baik? Anda selalu dapat menetapkan nilai ke beberapa variabel lain jika Anda membutuhkannya nanti, seperti yang dikatakan oleh orang lain.
Sebagai catatan, alih-alih perpipaan dari ps Anda bisa menggunakan
pgrep
ataupidof
.sumber
gunakan exec dari skrip bash setelah mendaftarkan pid ke file:
contoh:
misalkan Anda memiliki skrip bernama "forever.sh" yang ingin Anda jalankan dengan args p1, p2, p3
kode sumber forever.sh:
buat reaper.sh:
jalankan forever.sh melalui reaper.sh:
forever.sh tidak lebih dari mencatat baris ke syslog setiap 5 detik
Anda sekarang memiliki pid di /var/run/forever.sh.pid
dan forever.sh menjalankan aok. syslog grep:
Anda bisa melihatnya di tabel proses:
sumber
exec "$@"
bukanexec $*
. Secara teknis apa yang perlu Anda pertahankan bukanlah spasi putih tetapi kemunculan karakter dalam parameter shell IFS (yang default untuk spasi, tab, dan baris baru).Di bash shell alternatif untuk
$!
mungkin adalahjobs -p
built-in. Dalam beberapa kasus,!
in$!
akan diinterpretasikan oleh shell sebelum (atau bukannya) ekspansi variabel, yang mengarah ke hasil yang tidak terduga.Ini, misalnya, tidak akan berfungsi:
sementara ini akan:
sumber
Anda dapat menggunakan sesuatu seperti:
Atau
Dua perintah dapat berupa sambungan menggunakan
;
atau&&
. Dalam kasus kedua, pid akan ditetapkan hanya jika perintah pertama berhasil. Anda bisa mendapatkan id proses dari$pid
.sumber
$!
setelah&&
atau;
tidak akan pernah memberi Anda PID proses dimulai untuk sisi kiri pemisah perintah.$!
hanya diatur untuk proses yang diluncurkan secara tidak sinkron (mis. biasanya dengan&
tetapi beberapa shell juga memiliki metode lain).Ini sedikit jawaban hack-y dan kemungkinan tidak akan bekerja untuk kebanyakan orang. Ini juga merupakan metode risiko keamanan yang sangat besar, jadi jangan lakukan itu kecuali Anda yakin Anda akan aman dan inputnya sudah disanitasi dan ... yah, Anda mengerti.
Kompilasi program C kecil di sini menjadi biner yang disebut
start
(atau apa pun yang Anda inginkan), kemudian jalankan program Anda sebagai./start your-program-here arg0 arg1 arg2 ...
Singkatnya, ini akan mencetak PID
stdout
, lalu memuat program Anda ke dalam proses. Seharusnya masih memiliki PID yang sama.sumber
stdout
sepertinya tidak dicatat dalam contoh ini:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
sleep 10 & PID_IS=$!; echo $PID_IS