C'è un modo per lo script di shell di sapere quale programma lo ha eseguito?


13

Nel mondo * nix, c'è un modo per lo script di shell di avere informazioni su quale programma lo ha eseguito?


Esempio:

/path/to/script1 /path/to/script_xyz

in questo scenario immaginario, script_xyzavrebbe informazioni sul percorso ( /path/to/script1)

o

PID di processo

di entità che l'hanno eseguita.

Nota: sono curioso di conoscere soluzioni e approcci diversi, non mi aspetto esattamente che ciò sia effettivamente possibile


3
L'oggetto chiede quale programma ha eseguito lo script. Ma la tua vera domanda sembra chiedere l' interprete della sceneggiatura. Su quale dei due la tua domanda è davvero?
Kasperd,

@kasperd Hai ragione. La domanda riguardava il programma, ma in realtà è un interprete. Ecco perché ho sentito che questo non è possibile in primo luogo.
Miloš Đakonović,

Risposte:


23

C'è spesso confusione tra processo di fork ed esecuzione.

Quando lo fai al prompt di una bashshell.

$ sh -c 'exec env ps'

Il processo P1 che emette quel $prompt sta attualmente eseguendo il bashcodice. Tale bashcodice genera un nuovo processo P2 che viene /bin/sheseguito /usr/bin/enve quindi eseguito /bin/ps.

Così P2 è a sua volta il codice di esecuzione bash, sh, enve ps.

ps(o qualsiasi altro comando come uno script che utilizzeremo invece qui) non ha modo di sapere che è stato eseguito dal envcomando.

Tutto quello che può fare è scoprire qual è il suo ID di processo genitore, che in questo caso sarebbe P1 o 1se P1 è morto nell'intervallo o su Linux un altro processo che è stato designato come subreaper anziché 1.

Può quindi interrogare il sistema per quale comando è attualmente in esecuzione quel processo (come con readlink /proc/<pid>/exesu Linux) o quali argomenti sono passati all'ultimo comando che ha eseguito (come con ps -o args= -p <pid>).

Se vuoi che la tua sceneggiatura sappia cosa l'ha invocata, un modo affidabile sarebbe quello di farlo dire al chiamante. Ciò potrebbe essere fatto ad esempio tramite una variabile d'ambiente. Ad esempio script1potrebbe essere scritto come:

#! /bin/sh -
INVOKER=$0 script2 &

E script2:

#! /bin/sh -
printf '%s\n' "I was invoked by $INVOKER"
# and in this case, we'll probably find the parent process is 1
# (if not now, at least one second later) as script1 exited just after
# invoking script2:
ps -fp "$$"
sleep 1
ps -fp "$$"
exit

$INVOKERconterrà ( generalmente ) un percorso per script1. In alcuni casi, tuttavia, potrebbe essere un percorso relativo e il percorso sarà relativo alla directory di lavoro corrente al momento script1dell'avvio. Quindi, se si script1modifica la directory di lavoro corrente prima di chiamare script2, script2si otterranno informazioni errate su ciò che l'ha chiamato. Quindi potrebbe essere preferibile assicurarsi che $INVOKERcontenga un percorso assoluto (preferibilmente mantenendo il nome di base) come scrivendo script1come:

#! /bin/sh -
mypath=$(
  mydir=$(dirname -- "$0") &&
  cd -P -- "$mydir" &&
  pwd -P) && mypath=$mypath/$(basename -- "$0") || mypath=$0

... some code possibly changing the current working directory
INVOKER=$mypath script2

Nelle shell POSIX, $PPIDconterrà il pid del genitore del processo che ha eseguito la shell al momento dell'inizializzazione della shell. Successivamente, come visto sopra, il processo genitore può cambiare se il processo di id $PPIDmuore.

zshnel zsh/systemmodulo di interrogare la corrente pid genitore della shell corrente (sotto-) con $sysparams[ppid]. Nelle shell POSIX, è possibile ottenere l' attuale ppid del processo che ha eseguito l'interprete (supponendo che sia ancora in esecuzione) con ps -o ppid= -p "$$". Con bash, puoi ottenere il ppid della (sotto-) shell corrente con ps -o ppid= -p "$BASHPID".


8

Sì, un programma può sapere chi è il suo genitore.

Per illustrare, creiamo due script bash. Il primo riporta il suo PID e avvia il secondo script:

$ cat s1.sh
#!/bin/bash
echo s1=$$
bash s2.sh

Il secondo script riporta il suo ID processo, il PID del suo genitore e la riga di comando utilizzata per eseguire il genitore:

$ cat s2.sh
#!/bin/bash
echo s2=$$ PPID=$PPID
echo "Parent command: $(ps -o cmd= -q $PPID)"

Ora eseguiamolo:

$ bash s1.sh
s1=17955
s2=17956 PPID=17955
Parent command: bash s1.sh

Come puoi vedere il secondo script, infatti, conosce il PID del suo genitore. Usando ps, quel PID rivela la riga di comando usata per invocare il genitore.

Per una discussione del PPID più approfondita, vedi la risposta di Stéphane Chazelas .


Grazie. Esecuzione tuoi script di esempio che ricevo s1, s2e PPIDvalori, ma poi, in più righe dopo ERROR: Unsupported SysV option.e diverse linee con ulteriori spiegazioni e - valore vuoto perParent command
Miloš Đakonović

John sta usando alcune funzionalità ps che non sono disponibili (o sono fornite in modo diverso) sulla tua piattaforma, controlla la pagina man ps (1).
Jasen,

@Miloshio Ho provato quanto sopra usando psdal procps-ngpacchetto, versione 3.3.12. Come ha suggerito Jasen, probabilmente stai usando una versione diversa che potrebbe richiedere una sintassi diversa per stampare la riga di comando del genitore. Prova ps -f | grep $PPID.
Giovanni 1024,
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.