获取当前子shell的pid

时间:2013-12-22 03:21:16

标签: bash sh

我正在尝试获取当前正在执行的子shell的pid - 但$$仅返回父pid:

#!/usr/bin/sh

x() {
  echo "I am a subshell x echo 1 and my pid is $$"
}

y() {
  echo "I am a subshell y echo 1 and my pid is $$"
}


echo "I am the parent shell and my pid is $$"
x &
echo "Just launched x and the pid is $! "

y &
echo "Just launched y and the pid is $! "

wait

输出

I am the parent shell and my pid is 3107
Just launched x and the pid is 3108
I am a subshell x echo 1 and my pid is 3107
Just launched y and the pid is 3109
I am a subshell y echo 1 and my pid is 3107

正如您在上面所看到的,当我从我已经背景的函数运行$$时,它不会像我从父shell那样$!显示PID。

6 个答案:

答案 0 :(得分:38)

现代bash

如果您正在运行bash v4或更高版本,子shell的PID可在$BASHPID中使用。例如:

$ echo $$ $BASHPID ; ( echo $$ $BASHPID  )
32326 32326
32326 1519

在主shell中,$BASHPID$$相同。在子shell中,它被更新为子shell的PID。

旧bash(版本3.x或更早版本)

在第4版之前,您需要workaround

$ echo $$; ( : ; bash -c 'echo $PPID' )
11364
30279

(帽子小贴士:kubanczyk)

为什么要结肠?

请注意,如果没有冒号,解决办法工作:

$ echo $$; ( bash -c 'echo $PPID' )
11364
11364

看来,在上面,从未创建子shell,因此第二个语句返回主shell的PID。相比之下,如果我们在parens中放入两个语句,则会创建子shell并且输出正如我们所期望的那样。即使另一个语句仅仅是冒号:,也是如此。在shell中,:是一个无操作:它什么都不做。在我们的例子中,它确实强制创建子壳,这足以完成我们想要的任务。

短跑

在类似debian的系统上,dash是默认shell(/bin/sh)。 PPID方法适用于dash,但还有另一种转折:

$ echo $$; (  dash -c 'echo $PPID' ) 
5791
5791
$ echo $$; ( : ; dash -c 'echo $PPID' )
5791
5791
$ echo $$; (  dash -c 'echo $PPID'; : )   
5791
20961

使用dash,在命令之前放置:命令是不够的,但将其放在is之后。

POSIX

PPID包含在POSIX specification

可移植性

mklement0报告以下内容适用于bashdash zsh ,但不是 {{1} }:

ksh

答案 1 :(得分:5)

输出正确。

这是来自bash的手册页。

  

特殊参数

     

shell专门处理几个参数。这些参数只能被引用;不允许分配给他们。

     

*从1开始扩展到位置参数。当扩展发生在双引号内时,它会扩展为单个单词,其值为each                     参数由IFS特殊变量的第一个字符分隔。也就是说,"$*"相当于"$1c$2c...",其中c是第一个字符                     IFS变量的值。如果未设置IFS,则参数由空格分隔。如果IFS为null,则参数在没有插入分隔符的情况下连接   @从1开始扩展到位置参数。当扩展发生在双引号内时,每个参数都会扩展为单独的单词。那                     是,"$@"等价于"$1" "$2" ...如果双引号扩展发生在一个单词中,则第一个参数的扩展与原始单词的开头部分连接,并扩展最后一个参数加上原始单词的最后一部分。没有位置时                     参数,"$@"$@扩展为空(即,它们被删除)   #扩展为十进制位置参数的数量   ?扩展到最近执行的前台管道的退出状态   -扩展为调用时指定的当前选项标志,set builtin命令或shell本身设置的那些(例如-i选项)。
  $扩展为shell的进程ID。在()子shell中,它扩展为当前shell的进程ID,而不是子shell   !扩展到最近执行的后台(异步)命令的进程ID。

要在子shell中获取PID,可以使用BASHPID。这是一个仅限bash的env变量。

您的新脚本将如下所示。

#!/bin/bash

x() {
  echo "I am a subshell x echo 1 and my pid is $BASHPID"
}

y() {
  eval echo "I am a subshell y echo 1 and my pid is $BASHPID"
}


echo "I am the parent shell and my pid is $$"
x &
echo "Just launched x and the pid is $! "

y &
echo "Just launched y and the pid is $! "

wait

答案 2 :(得分:1)

@ John1024的答案很好,但是那里有一个小问题。

当命令像(...)一样运行时,该命令将在新的子进程中运行,因此

( : ; bash -c 'echo $PPID' ) 

将返回(...)的process_id,而不是调用(...)的函数的进程ID。

如果需要函数的process_id,则可以运行:

$SHELL -c 'echo $PPID'

和process_id将输出到stderr

如果要通过变量获取函数的process_id,可以运行:

$SHELL -c 'echo $PPID' | read -s func_pid

然后您可以从变量$ {func_pid}中获取pid。

注意:请勿在(...)中运行此命令,否则将返回(...)的process_id

答案 3 :(得分:0)

环境:

SUSE Linux Enterprise Server 10 SP2(i586)

GNU bash,版本3.1.17(1)-release(i586-suse-linux) 版权所有(C)2005 Free Software Foundation,Inc。

#!/usr/bin/sh

x() {
  mypid=$(awk 'BEGIN {print PROCINFO["ppid"] ; exit}')
  echo "I am a subshell x echo 1 and my pid is $mypid"
}

y() {
  mypid=$(awk 'BEGIN {print PROCINFO["ppid"] ; exit}')
  echo "I am a subshell y echo 1 and my pid is $mypid"
}


echo "I am the parent shell and my pid is $$"
x &
echo "Just launched x and the pid is $! "

y &
echo "Just launched y and the pid is $! "

wait

结果:

I am the parent shell and my pid is 27645
Just launched x and the pid is 27646
Just launched y and the pid is 27647
I am a subshell y echo 1 and my pid is 27647
I am a subshell x echo 1 and my pid is 27646

答案 4 :(得分:0)

如果您使用Linux内核,则可以使用Linux内核的/proc/self功能来做到这一点:

最简单的形式:cd -P /proc/self && basename "${PWD}"

要保留PWDOLDPWD变量:PWD_BACKUP="${PWD}";OLDPWD_BACKUP="${OLDPWD}";cd -P /proc/self && basename "${PWD}";cd "${PWD_BACKUP}";OLDPWD="${OLDPWD_BACKUP}"

例如:

$ cd -P /proc/self && basename "${PWD}"
26758
$ (cd -P /proc/self && basename "${PWD}")
26959
$ (cd -P /proc/self && basename "${PWD}")
26961
$ 

答案 5 :(得分:0)

最好使用 function test(value){ return value+ “hi”; } 而不是John1024答案中显示的技巧(这些技巧目前在我撰写答复时无法在现代shell中使用)。

看到以下问题: https://unix.stackexchange.com/questions/484442/how-can-i-get-the-pid-of-a-subshell