Come posso ottenere il pid di una subshell?


13

Come posso ottenere il pid di una subshell?

Per esempio:

$ echo $$
16808

Questo non funziona, perché la shell originale si espande $$:

$ ( echo $$ )
16808

Perché la virgoletta singola non funziona? Dopo che la shell originale ha rimosso la singola virgoletta, la subshell non si espande $$in sé?

$ ( echo '$$' )
$$

Perché evalnon funziona neanche? È evalgestito dalla subshell? Perché mi dà il PID della shell originale?

$ ( eval echo '$$' )
16808

Grazie.


Suggerisco una riapertura, perché le domande sono sostanzialmente diverse secondo me ("come evitare l' $$espansione" rispetto a "diverso pid in subshell").
Peter - Ripristina Monica il

Risposte:


12

Oltre a bash's $BASHPID, puoi farlo in modo portabile con:

pid=$(exec sh -c 'echo "$PPID"')

Esempio:

(pid=$(exec sh -c 'echo "$PPID"'); echo "$$ $pid")

Puoi trasformarlo in una funzione:

# usage getpid [varname]
getpid(){
    pid=$(exec sh -c 'echo "$PPID"')
    test "$1" && eval "$1=\$pid"
}

Si noti che alcune shell (es. zshO ksh93) NON avviano un sottoprocesso per ogni subshell creato con (...); in tal caso, $pidpotrebbe essere la stessa $$cosa, il che è giusto, perché è il PID del processo da cui è getpidstato chiamato.


1
No. Ma per favore non dare per scontato che una subshell sia necessariamente eseguita in un sottoprocesso - questo non è il caso ksh93, per esempio.
mosvy,

1
Funzionerà bene in ksh93 - restituirà sempre il pid del processo da cui è stato chiamato. È (...)dall'esempio che potrebbe non generare un processo separato, come accade in bash.
mosvy,

1
Inoltre, ad alcune shell piace zsho yashottimizza a fork()per l'ultimo comando in una sottoshell. Potrebbero anche ottimizzare il fork per la subshell se è l'ultimo comando in uno script in modo che tu getpidpossa persino segnalare il genitore di $$. È possibile definire getpidcome: getpid(){ sh -c 'echo "$PPID"'; return; }per disabilitare evitare il problema.
Stéphane Chazelas,

1
@HaroldFischer 1. senza l' execottimizzazione o senza tale sh -c ...processo , il processo sarà un nipote, anziché un figlio del processo in cui $(...)viene utilizzata la sostituzione di un comando, e $PPIDsarà il pid della $(...)subshell. Questo è esattamente ciò che accade nell'esempio set -E+ trap ERRbash sopra.
mosvy

1
@HaroldFischer 2. test "$1"verifica se $1è una stringa vuota o meno - un modo rapido e sporco per verificare se a quella funzione è stato fornito un varnameargomento a cui assegnare il pid o meno; usare una funzione non è stata l' idea più brillante al 1 ° posto.
mosvy

18
$ echo $BASHPID
37152
$ ( echo $BASHPID )
18633

Dal manuale:

BASHPID

Si espande nell'ID processo del processo bash corrente. Ciò differisce da $$in determinate circostanze, come i subshell che non richiedono la reinizializzazione di bash.

$

Si espande nell'ID processo della shell. In una ()subshell, si espande nell'ID del processo della shell corrente, non nella subshell.

Relazionato:


Grazie. (1) Cosa significa "reinizializzato"? (2) Potresti anche considerare perché quei modi in cui ho provato non funzionano?
Tim

@ Tim Credo che questo si risponde con Gilles qui . Bash semplicemente non si aggiorna $$in subshells.
Kusalananda

Vuoi dire che dovrei sempre usare $ BASHPID al posto di $$ in ogni caso in bash? Quando dovrei usare quale?
Tim

@Tim Dipende dal fatto che tu, in una subshell, desideri ottenere l'ID del processo dello script o della subshell. Entrambe le possibilità sono fornite e qual è quella corretta dipende dall'applicazione. Non è possibile dare una risposta più specifica a questo.
Kusalananda

1
@Tim Il PID di una shell genitore di una subshell non può essere trovato in modo affidabile a meno che non si organizzi il salvataggio $BASHPIDin una variabile e lo si usi nella subshell. Esiste $PPID, ma questo è il PID principale della shell nello stesso senso in cui $$è il PID della shell (non è ripristinato in una sotthell). Non ci sono $BASHPPIDvariabili
Kusalananda
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.