bash中的奇怪行为(可能还有其他shell?)

时间:2016-09-05 14:07:10

标签: linux bash shell

当我这样做时:

/bin/bash -c 'cat /proc/$$/cmdline'

我得到的输出是:

cat/proc/25050/cmdline

而我预期的输出是:

/bin/bash -c 'cat /proc/$$/cmdline'

另一方面,当我这样做时:

/bin/bash -c 'echo $$; cat /proc/$$/cmdline'

我得到了预期的输出,即:

28259
/bin/bash-cecho $$; cat /proc/$$/cmdline

似乎$$是猫的pid而不是bash / sh的pid 这是为什么? shell是否进行某种解析并替换execve()样式?如果是这样,它甚至在替换之前如何知道猫的PID?

1 个答案:

答案 0 :(得分:4)

为了理解这种行为,我们必须弄清楚bash如何在命令行上执行传递给它的命令。关键是如果命令足够简单,没有fork (或clone或类似的东西)。

$ strace -f -e clone,execve /bin/bash -c 'cat /proc/$$/cmdline'
execve("/bin/bash", ["/bin/bash", "-c", "cat /proc/$$/cmdline"], [/* 80 vars */]) = 0
execve("/bin/cat", ["cat", "/proc/2942/cmdline"], [/* 80 vars */]) = 0
cat/proc/2942/cmdline+++ exited with 0 +++
$

OTOH如果命令更复杂,bash分叉:

$ strace -f -e clone,execve /bin/bash -c 'echo $$; cat /proc/$$/cmdline'
execve("/bin/bash", ["/bin/bash", "-c", "echo $$; cat /proc/$$/cmdline"], [/* 80 vars */]) = 0
2933
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff64e6779d0) = 2934
Process 2934 attached
[pid  2934] execve("/bin/cat", ["cat", "/proc/2933/cmdline"], [/* 80 vars */]) = 0
/bin/bash-cecho $$; cat /proc/$$/cmdline[pid  2934] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2934, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
$
  

似乎$$是猫的pid而不是bash / sh的pid。

实际上两者都是。 <{1}} bash s execve直接,所以一个成为另一个。

要了解no-fork行为究竟需要什么,我们需要查看源代码。这是评论:

cat

Source