Bashでは、この便利な変数があります。$ BASHPIDは常に、現在実行中のサブシェルのPIDを常に返します。 kshでサブシェルのPIDを取得するにはどうすればよいですか?たとえば、次のコードを参照してください。
#!/usr/bin/ksh93
echo "PID at start: $$"
function run_in_background {
echo "PID in run_in_background $$"
run_something &
echo "PID of backgrounded run_something: $!"
}
function run_something {
echo "*** PID in run_something: $$"
sleep 10;
}
run_in_background
echo "PID of run in background $!"
これは以下を出力します:
PID at start: 5328
PID in run_in_background 5328
*** PID in run_something: 5328
PID of backgrounded run_something: 5329
PID of run in background 5329
私が欲しいのは、サブシェルのPIDを出力する****
で始まる行です。この例では5329です。
Kshでは利用できないと思います。外部プロセスの実行を含むPOSIXソリューションがあります。
_sh -c 'echo $PPID'
_
Linuxでは、_readlink /proc/self
_も機能しますが、利点はありません(わずかに高速になる可能性があります。readlink
はあるが_$PPID
_はないBusyBoxのバリアントでは便利です。しかし、私はそうは思わない)。
シェルで値を取得するには、有効期間が短いサブサブシェルでそのコマンドを実行しないように注意する必要があることに注意してください。たとえば、p=$(sh -c 'echo $PPID')
は、コマンド置換内でsh
を呼び出すサブシェルの出力を表示する場合があります(そうでない場合、一部のシェルがそのケースを最適化します)。代わりに、実行
_p=$(exec sh -c 'echo $PPID')
_
希望どおりの結果を得ることができますが、run_somethingを別のスクリプトに入れる必要があります。正確な理由はわかりませんが、$$は、それを呼び出しているのと同じスクリプト内の関数で使用された場合、再評価されません。 $$の値は、スクリプトが解析されてから実行されるまでの間に1回割り当てられると思います。
run_in_background.sh
#
echo "PID at start: $$"
function run_in_background {
echo "PID in run_in_background $$"
./run_something.sh &
echo "PID of backgrounded run_something: $!"
}
run_in_background
echo "PID of run in background $!"
run_something.sh
#
echo "*** PID in run_something: $$"
sleep 10;
出力
PID at start: 24395
PID in run_in_background 24395
PID of backgrounded run_something: 24396
PID of run in background 24396
*** PID in run_something: 24396
# KSH_VERSION hasn't always been a nameref, nor has it always existed.
# Replace with a better test if needed. e.g.:
# https://www.mirbsd.org/cvs.cgi/contrib/code/Snippets/getshver?rev=HEAD
if [[ ${!KSH_VERSION} == .sh.version ]]; then
# if AT&T ksh
if builtin pids 2>/dev/null; then # >= ksh93 v- alpha
function BASHPID.get { .sh.value=$(pids -f '%(pid)d'); }
Elif [[ -r /proc/self/stat ]]; then # Linux / some BSDs / maybe others
function BASHPID.get { read -r .sh.value _ </proc/self/stat; }
else # Crappy fallback
function BASHPID.get { .sh.value=$(exec sh -c 'echo $PPID'); }
fi
Elif [[ ! ${BASHPID+_} ]]; then
echo 'BASHPID requires Bash, ksh93, or mksh >= R41' >&2
exit 1
fi
解決中に遭遇した answer by @Gilles の後に 別の問題 があったので、正しい答えが次の理論であるという理論を裏付ける簡単なテストプログラムをまとめました。
MYPID=$(exec sh -c 'echo $PPID')
exec
が不要な場合があることを確認しましたが、試したすべてのシェルで常に正しいpidを取得するには、それを使用することが唯一の方法であることを確認しました。これが私のテストです:
#!/bin/sh
pids() {
echo ------
pstree -pg $PPID
echo 'PPID = ' $PPID
echo '$$ = ' $$
echo 'BASHPID =' $BASHPID
echo -n 'sh -c echo $PPID = '; sh -c 'echo $PPID'
echo -n '$(sh -c '\''echo $PPID'\'') = '; echo $(sh -c 'echo $PPID')
echo -n '$(exec sh -c '\''echo $PPID'\'') = '; echo $(exec sh -c 'echo $PPID')
echo -n 'p=$(sh -c '\''echo $PPID'\'') = '; p=$(sh -c 'echo $PPID') ; echo $p
echo -n 'p=$(exec sh -c '\''echo $PPID'\'') = '; p=$(exec sh -c 'echo $PPID') ; echo $p
}
pids
pids | cat
echo -e "$(pids)"
とその出力
------
bash(5975,5975)---pidtest(13474,13474)---pstree(13475,13474)
PPID = 5975
$$ = 13474
BASHPID = 13474
sh -c echo $PPID = 13474
$(sh -c 'echo $PPID') = 13474
$(exec sh -c 'echo $PPID') = 13474
p=$(sh -c 'echo $PPID') = 13474
p=$(exec sh -c 'echo $PPID') = 13474
------
bash(5975,5975)---pidtest(13474,13474)-+-cat(13482,13474)
`-pidtest(13481,13474)---pstree(13483,13474)
PPID = 5975
$$ = 13474
BASHPID = 13481
sh -c echo $PPID = 13481
$(sh -c 'echo $PPID') = 13481
$(exec sh -c 'echo $PPID') = 13481
p=$(sh -c 'echo $PPID') = 13481
p=$(exec sh -c 'echo $PPID') = 13481
------
bash(5975,5975)---pidtest(13474,13474)---pidtest(13489,13474)---pstree(13490,13474)
PPID = 5975
$$ = 13474
BASHPID = 13489
sh -c echo $PPID = 13489
$(sh -c 'echo $PPID') = 13492
$(exec sh -c 'echo $PPID') = 13489
p=$(sh -c 'echo $PPID') = 13495
p=$(exec sh -c 'echo $PPID') = 13489
シバンのお気に入りのシェルを置き換えます:sh
、bash
、mksh
、ksh
など...
ケース2と3の結果が異なる理由や、ケース3の結果がシェル間で異なる理由がわかりません。 Arch Linux FWIWでbash
、ksh
、mksh
を試しました。
#!/bin/ksh
function os_python_pid {
/usr/bin/python -c 'import os,sys ; sys.stdout.write(str(os.getppid()))'
}
function os_Perl_pid {
/usr/bin/Perl -e 'print getppid'
}
echo "I am $$"
echo "I am $(os_python_pid) :: $(os_Perl_pid)"
function proce {
sleep 3
echo "$1 :: $(os_python_pid) :: $(os_Perl_pid)"
}
for x in aa bb cc; do
proce $x &
echo "Started: $!"
done