which shutdown
返回
/usr/bin/shutdown
我也尝试过sudo which shutdown
以防万一......但结果是一样的。
我理解了
lrwxrwxrwx 1 root root 9 Dec 13 03:38 /usr/bin/shutdown -> systemctl
我还可以做类似的事情(2 小时后关闭机器)
sudo shutdown -h +120
但如果我尝试一些像这样愚蠢的事情:
sudo systemctl -h +120
我收到一个错误...
当我发出时,shutdown
我是否实际上调用了/usr/bin/shutdown
?如果是这样,那么从关机到 systemctl 的链接实际上是如何工作的?
答案1
简短回答
程序可以知道它被调用时的名称;它通过检查来学习自己的名称argv[0]
。这允许相同的可执行文件在不同名称下表现不同(例子)或单个可执行文件,当通过不同命名的符号链接调用时,其行为会有所不同(例子)。
在你的情况下,实际的systemctl
可执行文件知道它是否被调用为systemctl
或shutdown
或其他。它会相应地调整其行为。
额外细节
参数数组由父进程设置。argv[0]
名称是约定(不是严格要求)。父进程可能会也可能不会遵循约定。当您从 shell 运行systemctl
或shutdown
时,shell 是父进程,它遵循约定;一般来说,shell 遵循约定。
不遵守惯例的一个例子是 的行为login
(以及试图模仿它的工具):login
在第零个参数中使用前导破折号来通知子 shell 它应该是登录 shell。假设登录 shell 是 Bash。在 shell 中将echo "$0"
显示-bash
,尽管可执行文件名为bash
。这个前导破折号是其他习俗。
您可以systemctl
使用任意名称运行。有些名称很特殊,它们会改变的行为systemctl
,这是为了支持您观察到的符号链接。在我的 Debian 12 中,这些是(其中包括)shutdown
和runlevel
。您不需要创建符号链接或副本来将任意内容传递argv[0]
给systemctl
,您可以使用exec -a
Bash。
使用任意示例argv[0]
systemctl
(假设可以通过 到达示例$PATH
。如果需要,请提供完整路径名。)
bash -c 'exec -a foo systemctl' # should behave like plain systemctl because foo is not a name that would change the behavior
bash -c 'exec -a shutdown systemctl --help' # should behave like shutdown --help
bash -c 'exec -a runlevel systemctl' # should behave like runlevel
实际上,您可以使用符号链接systemctl
(如您的shutdown
)并传递任意的argv[0]
。例如:
bash -c 'exec -a runlevel shutdown' # should behave like runlevel
修复你的“愚蠢的命令”
你的“愚蠢命令”
sudo systemctl -h +120
可以像这样修复:
sudo bash -c 'exec -a shutdown systemctl -h +120'
shutdown
这里根本没有使用命名的符号链接(它可能不存在),systemctl
而是直接调用可执行文件;它仍然表现得像shutdown
因为我们传递了正确的名称(shutdown
)作为argv[0]
。