“bash -c”コマンド実行で子プロセスが作られる時、作られない時

Bash,CentOS,Docker,Kubernetes,Linux,Ubuntu

はじめに

KubernetesのマニフェストファイルやDockerのビルドファイル、Docker Composeの設定ファイルを閲覧、編集することが増えてきました。

それらのファイルの中で bash -c というコマンドが実行されていることがあります。
bash の新しいプロセスを立ち上げ、 -c オプションで渡されたコマンドを実行する命令になります。

ps コマンドを使い、実行中の bash -c プロセスを見ていたところ、プロセスツリーの表示が時々で異なっていたため不思議に思い調べてみました。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

改めて、 bash -c って何?

bash -c "echo hello" といったように、 -c コマンドに文字列を渡すことで、文字列をコマンドとして実行させることができます。
多くの言語系で実装されている eval 関数のようなものですね。

# 10秒待ってからhelloが表示される
$ bash -c "echo hogehoge"
hogehoge

コマンドは ; で区切って複数実行させることもできます。

# 10秒待ってからhelloが表示される
$ bash -c "sleep 10; echo hello;"
hello

bash -c "sleep 10; echo hello;" を実行したときのプロセスツリー

ここで、 bash -c "sleep 10; echo hello;" というコマンドを実行します。

$ bash -c "sleep 10; echo hello;"

すかさず、別のターミナルで ps auf を実行します。 f オプションを付与すると子プロセスが親プロセスにぶら下がる形で表示されます。

$ ps auf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root        19  0.0  0.0  11840  2952 pts/1    Ss   11:01   0:00 bash
root        44  0.0  0.0  51760  3360 pts/1    R+   11:05   0:00  \_ ps auf
root         1  0.0  0.0  11840  2996 pts/0    Ss   11:01   0:00 /bin/bash
root        42  0.0  0.0  11700  2636 pts/0    S+   11:05   0:00 bash -c sleep 10; echo hello;
root        43  0.0  0.0   4376   672 pts/0    S+   11:05   0:00  \_ sleep 10

プロセスがいくつも表示されていますが、 bash -c コマンドを実行した結果は一番下の2つのプロセスになります。

PID(プロセスID) = 42 のプロセスは bash -c "sleep 10; echo hello;" を実行しています。(ダブルクォーテーションはどこに行ってしまったんだろう?9
このプロセスがら派生した PID = 43 の子プロセスが sleep 10 を実行しています。

bash -c コマンドを実行した場合、 -c オプションに渡されたコマンドが子プロセスとして実行されるようです。

bash -c "sleep 10" を実行したときのプロセスツリー

今度は、 bash -c "sleep 10" という、単一のコマンドを実行するような文字列を指定してみます。

$ bash -c "sleep 10;"

すかさず、別のターミナルで ps auf を実行します。

$ ps auf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root        19  0.0  0.0  11840  2952 pts/1    Ss   11:01   0:00 bash
root        46  0.0  0.0  51760  3524 pts/1    R+   11:11   0:00  \_ ps auf
root         1  0.0  0.0  11840  2996 pts/0    Ss   11:01   0:00 /bin/bash
root        45  0.0  0.0   4376   628 pts/0    S+   11:11   0:00 sleep 10

先程とは異なり、 bash -c "sleep 10;" というプロセスがなく、 sleep 10 が親プロセスにぶら下がらずに実行されている ことがわかります。

bash -c がツリー状になったりならなかったり。
ps aux | grep [b]ash といった形で実行中のプロセスを検索しているときに「あれ? bash 実行プロセスが見つからない。なぜだ?」となり、不思議に思っていました。

-c オプおションで実行されるコマンドが単一の場合にはプロセスがツリーにならない

どうやら、Bashでは、 -c で渡されたコマンドが単一のコマンドだった場合には子プロセスを作らないようです。
( おそらく exec sleep 10 のようなことをしているのではないと思います。 )

ひとこと

bach -c で指定したジョブが正しく動作しているか確認したい場合など、 ps aux | grep [b]ash で検索して見つからない場合に参考になれば幸いです。