KornシェルでサブシェルのPIDを取得する方法($ BASHPIDと同等)


8

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になります。

回答:


10

kshでは利用できないと思います。外部プロセスの実行を含むPOSIXソリューションがあります。

sh -c 'echo $PPID'

Linux上で、readlink /proc/self仕事もだろうが、私はどんな利点を見ることができない(それがわずかに速くなるかもしれません。それが持っているBusyBoxのバリアントに有用である可能性readlinkはありません$PPIDが、私はものがあるとは思いません)。

シェルで値を取得するためには、有効期間が短いサブサブシェルでそのコマンドを実行しないように注意する必要があることに注意してください。たとえば、コマンド置換内p=$(sh -c 'echo $PPID')で呼び出すサブシェルの出力を表示する場合がありますsh(そうでない場合、一部のシェルはそのケースを最適化します)。代わりに、実行

p=$(exec sh -c 'echo $PPID')

この提案はすでに見ましたが、機能していません。3番目のPIDが得られますが、月曜日に仕事に戻ったときにもう一度テストします。
Patkos Csaba

@PatkosCsaba kshではkshがフォークを最適化するため、おそらく機能しますが、bashなどの他のシェルでは、誤ってサブサブシェルのpidを取得しないように注意する必要があります。私の更新された答えを見てください。
Gilles「SO-悪をやめ

これは機能しています。$(exec sh -c 'echo $PPID')ただし、最初の単純なコマンドsh -c 'echo $PPID'は3番目のPIDを提供します。ソリューションに感謝します。受け入れた。
Patkos Csaba

1
@FranklinYuどちらもサブシェルを作成していないためです。Bash (sh -c 'echo $PPID')はサブシェルを作成しないように最適化します。と対比(sh -c 'echo $PPID'; true)。この最適化は$BASHPID、サブシェルが終了する前に最後にアクセスしようとした場合にのみ有効です。つまり、値を使用して何も実行できない場合のみです。だから、実際には、あなたは置き換えることができ$BASHPID$(sh -c 'echo $PPID')
Gilles「SO-悪をやめる」

1
@FranklinYu組み込みのものはないと思います。もちろん、移植可能なメソッドを使用できsh -c 'echo $PPID'ます。
Gilles「SO-邪悪なことをやめ

3

希望どおりの結果を得ることができますが、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

1
# 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

2つのニッチ:if [[ ${!KSH_VERSION} = .sh.version ]]; then(1つのみ=)およびelif [[ -z ${BASHPID+_} ]]; then-n二重の角括弧で暗黙を使用しないようにします。古いpdkshはそれを知りませんでした)。
mirabilos 14

0

私が抱えていた別の問題を解決しているときに遭遇した@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

シェバングでお気に入りのシェルを置き換えますshbashmkshksh、等...

ケース2と3の結果が異なる理由や、ケース3の結果がシェル間で異なる理由がわかりません。私が試しましたbashkshそしてmkshArch Linux FWIWで。


0
#!/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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.