Solusi 1:
Apa yang bisa lebih sederhana dari echo $!
? Sebagai satu baris:
myCommand & echo $!
Solusi 2:
Anda dapat menggunakan sh -c
dan exec
untuk mendapatkan PID perintah bahkan sebelum itu berjalan.
Untuk memulai myCommand
, agar PID-nya dicetak sebelum mulai dijalankan, Anda dapat menggunakan:
sh -c 'echo $$; exec myCommand'
Cara kerjanya:
Ini memulai shell baru, mencetak PID dari shell tersebut, dan kemudian menggunakan exec
bawaan untuk mengganti shell dengan perintah Anda, memastikannya memiliki PID yang sama. Saat shell Anda menjalankan perintah dengan exec
bawaan, shell Anda sebenarnya menjadi perintah itu, daripada perilaku yang lebih umum dari forking salinan baru dari dirinya sendiri, yang memiliki PID tersendiri dan yang kemudian menjadi perintah.
Saya menemukan ini jauh lebih sederhana daripada alternatif yang melibatkan eksekusi asinkron (dengan &
), kontrol tugas, atau menelusuri dengan ps
. Pendekatan itu baik-baik saja, tetapi kecuali Anda memiliki alasan khusus untuk menggunakannya--misalnya, mungkin perintah sudah berjalan, dalam hal ini mencari PID-nya atau menggunakan kontrol pekerjaan akan masuk akal--saya sarankan mempertimbangkan cara ini terlebih dahulu. (Dan saya pasti tidak akan mempertimbangkan untuk menulis skrip yang rumit atau program lain untuk mencapai hal ini).
Jawaban ini menyertakan contoh teknik ini.
Bagian dari perintah itu kadang-kadang dapat dihilangkan, tetapi biasanya tidak.
Bahkan jika shell yang Anda gunakan adalah gaya Bourne dan dengan demikian mendukung exec
bawaan dengan semantik ini, biasanya Anda tidak boleh mencoba menghindari penggunaan sh -c
(atau yang setara) untuk membuat yang baru, terpisah proses shell untuk tujuan ini, karena:
- Setelah shell menjadi
myCommand
, tidak ada shell yang menunggu untuk menjalankan perintah selanjutnya.sh -c 'echo $$; exec myCommand; foo
tidak akan dapat mencoba menjalankanfoo
setelah mengganti dirinya sendiri denganmyCommand
. Kecuali Anda sedang menulis skrip yang menjalankan ini sebagai perintah terakhirnya, Anda tidak bisa hanya menggunakanecho $$; exec myCommand
di shell tempat Anda menjalankan perintah lain. - Anda tidak dapat menggunakan subkulit untuk ini.
(echo $$; exec myCommand)
mungkin secara sintaksis lebih bagus daripadash -c 'echo $$; exec myCommand'
, tetapi saat Anda menjalankan$$
di dalam(
)
, ini memberikan PID dari shell induk, bukan dari subkulit itu sendiri. Tapi itu adalah PID subkulit yang akan menjadi PID dari perintah baru. Beberapa shell menyediakan mekanisme non-portabelnya sendiri untuk menemukan PID subkulit, yang dapat gunakan untuk ini. Secara khusus, di Bash 4,(echo $BASHPID; exec myCommand)
berhasil.
Terakhir, perhatikan bahwa beberapa shell akan melakukan pengoptimalan di mana mereka menjalankan perintah seolah-olah dengan exec
(yaitu, mereka melupakan forking terlebih dahulu) ketika diketahui bahwa shell tidak perlu melakukan apa pun sesudahnya. Beberapa shell mencoba melakukan ini kapan saja itu adalah perintah terakhir yang dijalankan, sementara yang lain hanya akan melakukannya ketika tidak ada perintah lain sebelum atau sesudah perintah, dan yang lain tidak akan melakukannya sama sekali. Efeknya adalah jika Anda lupa menulis exec
dan cukup gunakan sh -c 'echo $$; myCommand'
maka itu akan terkadang memberi Anda PID yang tepat di some sistem dengan beberapa kerang. Saya sarankan untuk tidak mengandalkan perilaku seperti itu, dan malah selalu menyertakan exec
ketika itu yang Anda butuhkan.
Solusi 3:
Bungkus perintah dalam skrip kecil
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
Solusi 4:
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 tambahan, alih-alih menyalurkan dari ps, Anda dapat menggunakan pgrep
atau pidof
.
Solusi 5:
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:
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"[email protected]\""
sleep 5
done
buat reaper.sh:
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "[email protected]"
jalankan forever.sh melalui reaper.sh:
./reaper.sh ./forever.sh p1 p2 p3 p4 &
forever.sh tidak lebih dari mencatat satu baris ke syslog setiap 5 detik
Anda sekarang memiliki pid di /var/run/forever.sh.pid
cat /var/run/forever.sh.pid
5780
dan forever.sh berjalan dengan baik. grep syslog:
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
Anda dapat melihatnya di tabel proses:
ps axuwww|grep 'forever.sh p1' |grep -v grep
root 5780 0.0 0.0 4148 624 pts/7 S 16:07 0:00 /bin/sh ./forever.sh p1 p2 p3 p4