Existe uma maneira de o shell script saber qual programa o executou?

13

No mundo * nix, existe uma maneira de o shell script ter informações sobre qual programa o executou?


Exemplo:

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

nesse cenário imaginário, script_xyzteria informações de caminho ( /path/to/script1)

ou

PID do processo

da entidade que o executou.

Nota: Estou curioso sobre diferentes soluções e abordagens, não espero exatamente que isso seja realmente possível

Miloš Đakonović
fonte
3
Seu assunto pergunta qual programa executou o script. Mas sua pergunta real parece estar pedindo o intérprete do script. Sobre qual dos dois é realmente a sua pergunta?
kasperd
@kasperd Você está certo. A pergunta era sobre o programa, mas isso é realmente intérprete. Por isso, senti que isso não é possível em primeiro lugar.
Miloš Đakonović

Respostas:

23

Muitas vezes há confusão entre bifurcação e execução de processos.

Quando você faz no prompt de um bashshell.

$ sh -c 'exec env ps'

O processo P1 que emite esse $prompt está atualmente executando o bashcódigo. Esse bashcódigo bifurca um novo processo P2 que executa /bin/she /usr/bin/envdepois executa /bin/ps.

Então P2 , por sua vez código executado bash, sh, enve ps.

ps(ou qualquer outro comando como um script que usaríamos aqui) não tem como saber que foi executado pelo envcomando.

Tudo o que você pode fazer é descobrir qual é o ID do processo pai, que nesse caso seria P1 ou 1se P1 morreu no intervalo ou no Linux outro processo que foi designado como subreader em vez de 1.

Em seguida, ele pode consultar o sistema para saber qual comando esse processo está executando atualmente (como readlink /proc/<pid>/exeno Linux) ou quais argumentos foram passados ​​para o último comando executado (como com ps -o args= -p <pid>).

Se você deseja que seu script saiba o que o invocou, uma maneira confiável seria pedir ao invocador. Isso pode ser feito, por exemplo, através de uma variável de ambiente. Por exemplo, script1poderia ser escrito como:

#! /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

$INVOKER( geralmente ) conterá um caminho para script1. Em alguns casos, pode ser um caminho relativo, e o caminho será relativo ao diretório de trabalho atual no momento em que foi script1iniciado. Portanto, se script1alterar o diretório de trabalho atual antes de ligar script2, script2obterá informações erradas sobre o que o chamou. Portanto, pode ser preferível garantir que $INVOKERo caminho seja absoluto (de preferência mantendo o nome da base), escrevendo script1como:

#! /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

Nos shells POSIX, $PPIDconterá o pid do pai do processo que executou o shell no momento da inicialização do shell. Depois disso, como visto acima, o processo pai pode mudar se o processo de identificação $PPIDmorrer.

zshno zsh/systemmódulo, pode consultar o actual pid pai do reservatório actual (sub) com $sysparams[ppid]. Nos shells POSIX, você pode obter o ppid atual do processo que executou o intérprete (assumindo que ele ainda esteja em execução) com ps -o ppid= -p "$$". Com bash, você pode obter o ppid do (sub) shell atual com ps -o ppid= -p "$BASHPID".

Stéphane Chazelas
fonte
8

Sim, um programa pode saber quem é seu pai.

Para ilustrar, vamos criar dois scripts bash. O primeiro relata seu PID e inicia o segundo script:

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

O segundo script relata seu ID do processo, o PID de seu pai e a linha de comando usada para executar o pai:

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

Agora, vamos executá-lo:

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

Como você pode ver, o segundo script, de fato, conhece o PID de seu pai. Usando ps, esse PID revela a linha de comando usada para chamar o pai.

Para uma discussão mais profunda sobre PPID, consulte a resposta de Stéphane Chazelas .

John1024
fonte
Obrigado. Executando seus exemplos de scripts que recebo s1, s2e PPIDvalores, mas, em seguida, em várias linhas depois ERROR: Unsupported SysV option.e várias linhas com explicação adicional e - valor vazio paraParent command
Miloš Đakonović
John está usando algum recurso ps que não está disponível (ou é fornecido de maneira diferente) na sua plataforma, consulte a página de manual do ps (1).
Jasen 23/07
@Miloshio Testei o acima usando pso procps-ngpacote, versão 3.3.12. Como Jasen sugeriu, você provavelmente está usando uma versão diferente, que pode exigir uma sintaxe diferente para imprimir a linha de comando dos pais. Tente ps -f | grep $PPID.
John1024