Soluzione 1:
Cosa può esserci di più semplice di echo $!
? Come una riga:
myCommand & echo $!
Soluzione 2:
Puoi usare sh -c
e exec
per ottenere il PID del comando anche prima funziona.
Per avviare myCommand
, in modo che il suo PID venga stampato prima che inizi l'esecuzione, puoi usare:
sh -c 'echo $$; exec myCommand'
Come funziona:
Questo avvia una nuova shell, stampa il PID di quella shell e poi usa exec
incorporato per sostituire la shell con il tuo comando, assicurandoti che abbia lo stesso PID. Quando la tua shell esegue un comando con exec
builtin, la tua shell sta effettivamente diventando quel comando, piuttosto che il comportamento più comune di biforcare una nuova copia di se stesso, che ha il proprio PID separato e che quindi diventa il comando.
Trovo che questo sia molto più semplice delle alternative che coinvolgono l'esecuzione asincrona (con &
), controllo del lavoro o ricerca con ps
. Questi approcci vanno bene, ma a meno che tu non abbia un motivo specifico per usarli, ad esempio forse il comando è già in esecuzione, nel qual caso avrebbe senso cercare il suo PID o usare il controllo del lavoro, suggerisco di considerare prima questo modo. (E certamente non prenderei in considerazione la possibilità di scrivere uno script complesso o un altro programma per raggiungere questo obiettivo).
Questa risposta include un esempio di questa tecnica.
Parti di quel comando potrebbero occasionalmente essere omesse, ma non di solito.
Anche se la shell che stai usando è in stile Bourne e quindi supporta exec
integrato con queste semantiche, generalmente non dovresti evitare di usare sh -c
(o equivalente) per creare un nuovo separato processo di shell per questo scopo, perché:
- Una volta che la shell è diventata
myCommand
, non c'è nessuna shell in attesa di eseguire i comandi successivi.sh -c 'echo $$; exec myCommand; foo
non sarebbe in grado di tentare di eseguirefoo
dopo aver sostituito se stesso conmyCommand
. A meno che tu non stia scrivendo uno script che lo esegua come ultimo comando, non puoi semplicemente usareecho $$; exec myCommand
in una shell dove stai eseguendo altri comandi. - Non puoi usare una subshell per questo.
(echo $$; exec myCommand)
potrebbe essere sintatticamente migliore dish -c 'echo $$; exec myCommand'
, ma quando esegui$$
all'interno di(
)
, fornisce il PID della shell madre, non della subshell stessa. Ma è il PID della subshell che sarà il PID del nuovo comando. Alcune shell forniscono i propri meccanismi non portatili per trovare il PID della subshell, cosa che potresti utilizzare per questo. In particolare, in Bash 4,(echo $BASHPID; exec myCommand)
funziona.
Infine, nota che alcune shell eseguiranno un'ottimizzazione in cui eseguono un comando come da exec
(cioè, rinunciano prima al fork) quando è noto che il guscio non avrà bisogno di fare nulla in seguito. Alcune shell provano a farlo ogni volta che è l'ultimo comando da eseguire, mentre altre lo faranno solo quando non ci sono altri comandi prima o dopo il comando, e altre non lo faranno affatto. L'effetto è che se dimentichi di scrivere exec
e usa solo sh -c 'echo $$; myCommand'
poi a volte darti il PID corretto su alcuni sistemi con alcuni conchiglie. Raccomando di non fare mai affidamento su tale comportamento e di includere sempre exec
quando è ciò di cui hai bisogno.
Soluzione 3:
Racchiudi il comando in un piccolo script
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
Soluzione 4:
Non conosco alcuna soluzione più semplice, ma non sta usando $! abbastanza buono? Puoi sempre assegnare il valore a qualche altra variabile se ne hai bisogno in seguito, come detto da altri.
Come nota a margine, invece di eseguire il piping da ps potresti usare pgrep
o pidof
.
Soluzione 5:
usa exec da uno script bash dopo aver registrato il pid in un file:
esempio:
supponi di avere uno script chiamato "forever.sh" che vuoi eseguire con gli argomenti p1,p2,p3
codice sorgente forever.sh:
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"[email protected]\""
sleep 5
done
crea un mietitore.sh:
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "[email protected]"
esegui forever.sh attraverso reaper.sh:
./reaper.sh ./forever.sh p1 p2 p3 p4 &
forever.sh non fa altro che registrare una riga su syslog ogni 5 secondi
ora hai il pid in /var/run/forever.sh.pid
cat /var/run/forever.sh.pid
5780
e forever.sh funziona correttamente. syslog grep:
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
puoi vederlo nella tabella dei processi:
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