如何在Korn Shell中获取subshel​​l的PID(相当于$ BASHPID)


8

在bash中,您有一个方便的变量:$ BASHPID wich始终返回当前运行的子Shell的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。

Answers:


10

我认为这在ksh中不可用。有一个POSIX解决方案,涉及运行外部过程:

sh -c 'echo $PPID'

在Linux上readlink /proc/self也可以,但是我看不到任何优势(它可能略快一些;它在具有BusyBox变体readlink但没有$PPID,但是我不认为有一个变体的情况下很有用)。

请注意,为了在shell中获取值,您需要注意不要在短暂的sub-sub shell中运行该命令。例如,p=$(sh -c 'echo $PPID')可能显示在sh命令替换内调用的子外壳程序的输出(或者可能不会,某些外壳程序会优化这种情况)。而是运行

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

我已经看到了这个建议,但是没有用。它给了我第三个PID ...但是,我星期一恢复工作时将再次对其进行测试。
Patkos Csaba

@PatkosCsaba在ksh中可能会起作用,因为ksh优化了fork,但是在其他bash等shell中,您需要注意不要意外获取sub-sub shell的pid。看到我更新的答案。
吉尔(Gilles)'所以

这是可行的:$(exec sh -c 'echo $PPID')但是最初的简单命令sh -c 'echo $PPID'给出了第三个PID。因此,感谢您的解决方案。公认。
Patkos Csaba

1
@FranklinYu这是因为两者都没有创建子外壳。Bash进行了优化(sh -c 'echo $PPID')以避免创建子外壳。与对比(sh -c 'echo $PPID'; true)。仅当您尝试$BASHPID在子shell退出之前最后访问时才启动此优化,即仅在您无法使用该值执行任何操作的情况下。因此在实践中,您可以将替换$BASHPID$(sh -c 'echo $PPID')
吉尔斯(Gilles)'所以

1
@FranklinYu我认为没有内置的东西。您当然可以使用可移植的方法sh -c 'echo $PPID'
吉尔斯(Gilles)'所以

3

您可以实现所需的功能,但需要将run_something放入单独的脚本中。我不确定为什么,但是在调用它的同一脚本中的函数中使用$$时,不会重新评估它。我猜想$$的值在脚本解析之后和执行之前分配一次。

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

两个nitpicks :(if [[ ${!KSH_VERSION} = .sh.version ]]; then仅一个=)和elif [[ -z ${BASHPID+_} ]]; then(避免-n在双方括号中使用隐式,旧的pdksh不知道)。
mirabilos 2014年

0

在解决我遇到的另一个问题的同时,我遇到了@Gilles回答后,我制定了一个快速测试程序,该程序支持正确答案是的理论:

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

我发现有时候exec并不需要,但是我确认使用它是在我尝试过的所有shell中始终获取正确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并且mksh在Arch 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.