Shell

/proc/self/environ 在某些 shell 中的奇怪行為;到底是怎麼回事?

  • June 10, 2021

我在 Debian GNU/Linux 9 上。我知道/proc是特別的,我知道什麼/proc/self

這個命令

sh -c '/bin/cat /proc/self/comm - </proc/self/comm'

產量

cat
sh

如果我使用dash而不是sh. 但是bash,ksh或者zsh結果是

cat
cat

取而代之/proc/self/stat的是,/proc/self/comm我可以確認這兩個cat-s 實際上是同一個過程。顯然外殼在引擎蓋下有所不同,沒關係。現在讓我們採取

sh -c '/bin/cat /proc/self/environ - </proc/self/environ'

看了以上,sh還是dash期待先看看catshell的環境,再看看shell的環境。它似乎有效(兩種環境很可能是相同的,所以很難判斷一切是否按預期工作,但我的觀點是:兩者都不environ是空的)。

使用bash,ksh或者zsh我期望看到cat兩次的環境,但它只列印了一次。分成兩種不同的情況:

  • bash -c '/bin/cat - </proc/self/environ'什麼也不列印,好像environ是空的;
  • bash -c '/bin/cat /proc/self/environ'按預期列印一些東西。

到底是怎麼回事?這不是commor的情況stat。為什麼不environ一樣?

$ uname -a
Linux barbaz 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1 (2018-04-29) x86_64 GNU/Linux

shell 之間的差異是由於程序設置的差異造成的。dash在分叉之前設置重定向,所以/proc/self指向外殼;bashzsh在分叉後設置它們,因此/proc/self指向新程序。您可以通過以下方式看到這種情況strace -f

  • strace -f dash -c '/bin/cat /proc/self/comm - </proc/self/comm'表演(除其他外)
 open("/proc/self/comm", O_RDONLY)       = 3
 fcntl(0, F_DUPFD, 10)                   = 10
 close(0)                                = 0
 fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
 dup2(3, 0)                              = 0
 close(3)                                = 0
 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f12581299d0) = 7743
 strace: Process 7743 attached
 [pid  7742] wait4(-1,  <unfinished ...>
 [pid  7743] execve("/bin/cat", ["/bin/cat", "/proc/self/comm", "-"], [/* 43 vars */]) = 0

/proc/self/comm在系統呼叫之前打開clone,這是程序分叉的地方);

  • strace -f bash -c '/bin/cat /proc/self/comm - </proc/self/comm'節目
 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fb506bdee10) = 8106
 strace: Process 8106 attached
 [... snip a ton of signal-handling setup ...]
 [pid  8106] open("/proc/self/comm", O_RDONLY) = 3
 [pid  8106] dup2(3, 0)                  = 0
 [pid  8106] close(3)                    = 0
 [pid  8106] execve("/bin/cat", ["/bin/cat", "/proc/self/comm", "-"], [/* 43 vars */]) = 0

/proc/self/comm在呼叫後打開clone,在子程序中,8106)。

了解為什麼environ顯示為空需要更多解釋。/proc/<pid>/environ打開時,核心保存一個指向任務的指針的副本mm_struct,其中包含指向環境的指針。但是execve,用於啟動cat程序的 ,會為程序創建一個新mm_struct。因此,重定向最終指向過時的資訊,當cat讀取其輸入時,它看不到它的真實環境。它確實看到的環境應該是其父環境的副本,但所涉及的 shell 在分叉和設置新環境(由 設置execve)之前對其進行清理。

引用自:https://unix.stackexchange.com/questions/467169