いくつかのシェルで `/proc/self/environ`の奇妙な動作、何が起こっていますか?

いくつかのシェルで `/proc/self/environ`の奇妙な動作、何が起こっていますか?

私はDebian GNU / Linux 9を使用しています。わかりました/proc非常に特別な、わかりました/proc/selfですか

このコマンド

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

生産する

cat
sh

dash代わりに使用するとパターンが似ていますsh。しかしbashkshまたはzsh結果は次のとおりです。

cat
cat

代わりに、/proc/self/stat私は両方が実際に同じプロセスであることを/proc/self/comm確認できます。cat明らかにフードの下の殻は異なります。大丈夫です。今私たちが持っていこう

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

上記を観察した後、shまたはdash私が見ると予想したものはcat後でシェルの環境です。うまくいくようです(とにかく両方の環境は同じである可能性が高いので、どうかを言うのは難しいです)。すべて期待どおりに動作しますが、私のポイントはどちらもenvironnullではないということです。

bashkshまたはzsh2回見ると予想した環境がありますが、cat印刷のみです。一度。 2つの状況に分けられます。

  • bash -c '/bin/cat - </proc/self/environ'何も印刷せず、environ空のように動作します。
  • bash -c '/bin/cat /proc/self/environ'期待どおりに何かを印刷します。

どうしたの?commそれともそうではありません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

答え1

シェル間の違いは、プロセス設定の違いによるものです。dashブランチの前にリダイレクトを設定して/proc/selfシェルをポイントbashし、zshブランチ後にこれを設定して/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、環境へのポインタを含みます。しかし、execvecatプロセスを開始するために使用されます。mm_structプロセス用の新しいプロセスの作成。したがって、リダイレクトは最終的に古い情報を指すようになり、cat入力を読むときに実際の環境を見ることはできません。環境を作り出すするseeは親環境のコピーと見なされますが、execve新しい環境を分岐して設定する前にそれをクリーンアップするシェルが含まれています。

関連情報