bashスクリプト(最初の行#! /bin/bash
)があり、do-doruns
bashコマンドラインから呼び出します。./do-doruns arg1 arg2 ...
このスクリプトは順番に scripts を呼び出し、./dorun a1 a2 a3 ...
より多くのレベルのスクリプトがあり、コンパイルされたプログラムを呼び出します。
ps
とを使用すると、dorun
その下で呼び出されるすべての実行中の項目にはps
その名前とコマンドライン引数が表示されます。たとえば、次のようになります。
/bin/bash /home/moss/path-to-dorun/dorun a1 a2 a3
など。ただし、どのdo-doruns
線も表示されません。確かに実行中です(サブプロセスが完了するのを待っています)。なぜそうしたのか理解できます。議論消えることはありますが(別のテストでshift
bashを使用すると引数が消えないことがわかりましたがps
)、その$0
コマンド名は消えません。
これが私の作業に邪魔になるわけではありませんが、必ず知りたい奇妙なミステリーです。物事のバージョンは次のとおりです。
uname -a
示す:Linux moss-Ubuntu-SMCSim 5.4.0-81-generic #91-Ubuntu SMP Thu Jul 15 19:09:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
bash --version
示す:GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
ps --version
表示される内容(おそらく奇妙なことに):ps from procps-ng UNKNOWN
この動作はこれに限定されず、より
ps
基本top
的に見えるように表示されます。最後に、これが重要な場合は、これらすべてがVirtualBox仮想マシンで実行されていることです。
vboxmanage --version
示す:7.0.4r154605
答え1
ps -C
これはoptionsが使用するコマンド名を変更し、grepと一致する方法(使用するフラグによって異なります)を変更するため、スクリプトの最初の行がどのように見えるかによって異なります。
次のようなものを使用してください
#!/bin/bash
コマンド名をスクリプト名に変更するため、do-dorunと表示されます。
使用
#!/bin/env bash
これは、コマンド名がbashのままであることを意味します。
両方のコマンドラインは同じように見えます。例えば/bin/bash myscriptname.sh arg1 arg2 arg3
答え2
eval
さらなる研究、つまりスクリプトを最小限のテストケースに縮小した結果、この動作はbashの組み込み機能を使用したために発生したことがわかりました。最小テストケースは次のとおりです。
#! /bin/bash
eval foo xyz
foo
実行する他のスクリプトはどこにありますか? (特にテストしていませんが、プログラムでもこれが発生する可能性があります。)
何が起こっているようであれば、シェルにコマンドeval
ラインオプションfork-exec aをbash
使用してコマンドラインを実行させます。-c
そのようなbash呼び出しのため、コマンドラインに空のタスクが表示されるようです。コマンドラインを読んだ後、bashは必要なプログラムだけを実行しているようです。
だから、このような動作をしたくない場合eval
。
把握するのを手伝ってくれてありがとう!
答え3
exec
後続のコマンドがexec
呼び出しシェルを置き換えるので、シェルのコマンドラインを変更する簡単な方法があります。/proc/pid/cmdline
ここで印刷物を美しくするという意見を考慮するとバージョン2です。ただし、evalを使用して変数に準備されたコマンドを実行する方法はexec
。
例v2:
#!/bin/bash
identifyMyself() {
echo "My cmdline: $0 My arg1: $1 My PID: $BASHPID"
echo "Kernel says:"
#cat -A /proc/$BASHPID/cmdline
#echo
readarray -d '' -t cmdline < /proc/$$/cmdline
#declare -p cmdline
printf '%s ' "${cmdline[@]}"
echo
}
identifyMyself "$1"
if [ -z "$1" ]
then
echo "calling myself with long parameters"
"$0" arg1 arg2 arg3 arg4
fi
if [ -z "$1" ]
then
dorun="$0 arg1 arg2 arg3 arg4"
echo "calling myself with long parameters by evaling a variable"
eval "${dorun}"
fi
if [ -z "$1" ]
then
echo "I am still here"
identifyMyself "$1"
fi
if [ -z "$1" ]
then
echo "execing myself with long parameters"
exec "$0" arg1 arg2 arg3 arg4
fi
if [ -z "$1" ]
then
echo "now I am gone"
identifyMyself "$1"
fi
出力:
$ ./bashtestv2_pid.sh
My cmdline: ./bashtestv2_pid.sh My arg1: My PID: 1444428
Kernel says:
/bin/bash ./bashtestv2_pid.sh
calling myself with long parameters
My cmdline: ./bashtestv2_pid.sh My arg1: arg1 My PID: 1444429
Kernel says:
/bin/bash ./bashtestv2_pid.sh arg1 arg2 arg3 arg4
calling myself with long parameters by evaling a variable
My cmdline: ./bashtestv2_pid.sh My arg1: arg1 My PID: 1444430
Kernel says:
/bin/bash ./bashtestv2_pid.sh arg1 arg2 arg3 arg4
I am still here
My cmdline: ./bashtestv2_pid.sh My arg1: My PID: 1444428
Kernel says:
/bin/bash ./bashtestv2_pid.sh
execing myself with long parameters
My cmdline: /home/user/bin/bashtestv2_pid.sh My arg1: arg1 My PID: 1444428
Kernel says:
/bin/bash /home/user/bin/bashtestv2_pid.sh arg1 arg2 arg3 arg4
コマンドラインが変更された場合は、実行後にPIDがどのように変わらないかを確認してください。eval
通常の通話のように機能します。あなたがコメントで言ったことは次のとおりです。しかし、あなた自身の答えでは正反対だと言います。暗黙eval
的exec
。