bashスクリプトを実行すると$ 0とすべてのパラメータが消えるのはなぜですか(psに表示されます)?

bashスクリプトを実行すると$ 0とすべてのパラメータが消えるのはなぜですか(psに表示されます)?

bashスクリプト(最初の行#! /bin/bash)があり、do-dorunsbashコマンドラインから呼び出します。./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線も表示されません。確かに実行中です(サブプロセスが完了するのを待っています)。なぜそうしたのか理解できます。議論消えることはありますが(別のテストでshiftbashを使用すると引数が消えないことがわかりましたが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通常の通話のように機能します。あなたがコメントで言ったことは次のとおりです。しかし、あなた自身の答えでは正反対だと言います。暗黙evalexec

関連情報