为啥 $$ 返回与父进程相同的 id?

Posted

技术标签:

【中文标题】为啥 $$ 返回与父进程相同的 id?【英文标题】:Why is $$ returning the same id as the parent process?为什么 $$ 返回与父进程相同的 id? 【发布时间】:2014-01-30 13:46:49 【问题描述】:

我在使用 Bash 时遇到问题,我不知道为什么。 在shell下,我输入:

echo $$    ## print 2433
(echo $$)  ## also print 2433
(./getpid) ## print 2602

“getpid”是一个获取当前pid的C程序,如:

   int main() 
    printf("%d", (int)getpid());
    return 0;
   

让我困惑的是:

    我认为“(command)”是一个子进程(对吗?),我认为它的 pid 应该与它的父 pid 不同,但它们是相同的,为什么...... 当我使用我的程序在括号之间显示 pid 时,它显示的 pid 是不同的,对吗? '$$' 是不是类似于宏?

你能帮帮我吗?

【问题讨论】:

请注意,getpid 会显示不同的进程 ID,即使它没有在子 shell 中运行。 @Marian echo $$ $BASHPID ; ( echo $$ $BASHPID ) 证明确实如此。圆括号创建一个子外壳。这些语句可能会更改变量值,并且父 shell 不能看到这些更改。这是作为fork() 操作实现的。 【参考方案1】:

$$被定义为返回子shell中父进程ID;来自“特殊参数”下的手册页:

$ 扩展为 shell 的进程 ID。在 () 子shell 中,它扩展为当前shell 的进程ID,而不是子shell。

bash4中,可以通过BASHPID获取子进程ID。

~ $ echo $$
17601
~ $ ( echo $$; echo $BASHPID )
17601
17634

【讨论】:

"parent" 有点误导(至少对我来说是这样),它实际上是“***”外壳。例如:echo $$; (echo $$; (echo $$)) 三次回显同一个 pid 对;我应该说该值是从父 shell 继承的(它从 its 父 shell 等继承了它的值)。*** shell 最初设置它,而不是从其(非 shell)父进程继承。 $ Expands to the process ID of the shell 是吗? echo $ 只是与文字 $ 相呼应。 好吧,我真的不知道这意味着什么,但echo $BASHPID 在 bash 4 和 5 中工作(但在 MacOS 上不是 3.2.57 版) 所有参数扩展都以$开头,但$也是特殊参数之一的名称。 $#@*等是一些特殊参数; $$$#$@$* 等是扩展为每个值的表达式。【参考方案2】:

您可以使用以下方法之一。

$! 是最后一个后台进程的 PID。 kill -0 $PID 检查它是否仍在运行。 $$ 是当前 shell 的 PID。

【讨论】:

如果我们在谈论后台进程,第二个子弹不应该是kill -0 $!吗? PID 默认没有设置任何东西。【参考方案3】:
    括号调用subshell in Bash。由于它只是一个子外壳,它可能具有相同的 PID - 取决于实现。 您调用的 C 程序是一个单独的进程,它有自己唯一的 PID - 是否在子 shell 中无关紧要。 $$ 是 Bash 中 the current script PID 的别名。请参阅differences between $$ and $BASHPID here,以及正上方包含嵌套级别的附加变量$BASH_SUBSHELL

【讨论】:

【参考方案4】:

如果您希望 C 程序打印 shell 的 PID,请尝试 getppid()

【讨论】:

或者如果你使用 Rust,只需尝试nix::unistd::getppid(),它将获得当前进程父进程的 pid - docs.rs/nix/0.18.0/nix/unistd/fn.getppid.html【参考方案5】:

这是获得正确 pid 的一种通用方法

pid=$(cut -d' ' -f4 < /proc/self/stat)

同样适用于 sub

SUB()
    pid=$(cut -d' ' -f4 < /proc/self/stat)
    echo "$$ != $pid"


echo "pid = $$"

(SUB)

检查输出

pid = 8099
8099 != 8100

【讨论】:

好主意,但这不会让你得到 shell 运行的 fork 的 pid 来捕获 cut 的输出吗?如果我运行它两次,一次使用 echo $(...) 一次没有,然后我会得到不同的答案。【参考方案6】:

如果您询问如何获取已知命令的 PID,它类似于以下内容:

如果您发出了以下命令 #发出的命令是***

dd if=/dev/diskx of=/dev/disky


那么你会使用:

PIDs=$(ps | grep dd | grep if | cut -b 1-5)

这里发生的事情是将所有需要的唯一字符通过管道传输到一个字段,并且可以使用该字段来回显

回显 $PIDs

【讨论】:

【参考方案7】:

如果您想要一个简单的 shell 脚本来获取带有变量的最大 PID,请执行此操作

pid=$(cat /proc/sys/kernel/pid_max)
echo $pid

这将打印出最大的 PID。

【讨论】:

以上是关于为啥 $$ 返回与父进程相同的 id?的主要内容,如果未能解决你的问题,请参考以下文章

使用fork创建子进程时,父ID与父ID不同[重复]

为啥 IPC::Open2::open2 返回父进程 ID?

进程与进程间通信

Unix环境高级编程fork函数总结

python多进程——fork()

C linux中子进程与父进程之间的通信:父进程不阻塞