Часто возникает путаница между процессом разветвления и выполнением.
Когда вы делаете по приглашению bash
оболочки.
$ sh -c 'exec env ps'
Процесс P1, выдающий это $
приглашение, в настоящий момент выполняет bash
код. Этот bash
код разветвляет новый процесс P2, который выполняется, /bin/sh
который затем выполняется /usr/bin/env
, который затем выполняется /bin/ps
.
Таким образом , P2 , в свою очередь выполняется код bash
, sh
, env
и ps
.
ps
(или любая другая команда, такая как скрипт, который мы использовали бы здесь) не может знать, что она была выполнена env
командой.
Все это можно сделать , это выяснить , что его родительский процесс идентификатор, который в этом случае будет либо P1 или 1
если P1 умер в промежутке или на Linux другого процесса , который был назначен в качестве subreaper вместо 1
.
Затем он может запросить у системы, какая команда выполняется в данный момент (например, readlink /proc/<pid>/exe
в Linux) или какие аргументы были переданы последней команде, которую он выполнил (например, в ps -o args= -p <pid>
).
Если вы хотите, чтобы ваш сценарий знал, что его вызвало, надежным способом было бы, чтобы вызывающий сообщал об этом. Это может быть сделано, например, через переменную окружения. Например, script1
может быть написано как:
#! /bin/sh -
INVOKER=$0 script2 &
И 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
будет ( обычно ) содержать путь к script1
. В некоторых случаях это может быть относительный путь, и путь будет относительно текущего рабочего каталога на момент script1
запуска. Так что, если script1
изменит текущий рабочий каталог перед вызовом script2
, script2
получит неверную информацию относительно того, что вызвало его. Поэтому может быть предпочтительнее убедиться, что он $INVOKER
содержит абсолютный путь (предпочтительно с сохранением базового имени), например, записав в script1
виде:
#! /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
В оболочках POSIX $PPID
будет содержаться pid родительского процесса, который выполнил оболочку во время инициализации этой оболочки. После этого, как видно выше, родительский процесс может измениться, если процесс id $PPID
умирает.
zsh
в zsh/system
модуле, может запросить текущий родительский pid текущей (под) оболочки с помощью $sysparams[ppid]
. В оболочках POSIX вы можете получить текущий ppid процесса, который выполнил интерпретатор (при условии, что он все еще выполняется) ps -o ppid= -p "$$"
. С помощью bash
вы можете получить ppid текущей (под) оболочки с помощью ps -o ppid= -p "$BASHPID"
.