我有一个 bash 脚本(第一行#! /bin/bash
)do-doruns
,我从 bash 命令行调用它./do-doruns arg1 arg2 ...
该脚本依次调用 script ./dorun a1 a2 a3 ...
,并且还有更多级别的 script ,然后调用编译后的程序。
当使用 和 进行查看时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
,以及可能如何将其与 grep 匹配(取决于您使用的标志)。
使用类似的东西
#!/bin/bash
会将命令名称更改为脚本的名称,因此这将显示为 do-dorun。
使用
#!/bin/env bash
意味着命令名称将保留为 bash。
两者的命令行看起来都是一样的,例如/bin/bash myscriptname.sh arg1 arg2 arg3
答案2
进一步的研究,即将我的脚本减少到最小的测试用例,表明这种行为是由于使用 bash 的eval
内置函数造成的。最小的测试用例是:
#! /bin/bash
eval foo xyz
哪里foo
有其他要运行的脚本。 (这也可能发生在程序中,尽管我没有专门测试它。)
似乎发生的情况是eval
导致 shellbash
使用-c
命令行选项 fork-exec a 来运行命令行。看来这样的 bash 调用会导致命令行显示为空的作业,我想是因为命令行已被读取,然后 bash 只执行所需的程序。
因此,如果我不想要这种行为,似乎我应该避免使用eval
.
谢谢你帮我想清楚!
答案3
有一种简单的方法可以更改 shell 的命令行,exec
因为后面的命令exec
会替换调用 shell。考虑到关于美化/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
。