ExecStart=@/path/to/executable 上的 Systemd 服务前缀不会更改“argv[0]”

ExecStart=@/path/to/executable 上的 Systemd 服务前缀不会更改“argv[0]”

根据man systemd.service使用前缀的手册@是这样说的:

如果可执行路径以“@”为前缀,则第二个指定的标记将作为“argv[0]”传递到执行的进程(而不是实际的文件名),后面跟着指定的其他参数。

但是当我使用 bash 脚本或 python 脚本运行服务时,文件名或 argv[0] 不起作用。仅当我使用用 C 语言编写的程序时,这才有效。

在我的服务中,我有:

[Unit]
Description=After service Number: 1

[Service]
Type=oneshot
ExecStart=@/home/edgar/bin/script "after-1-service" "1" "Args from after-service"

[Install]
WantedBy=multi-user.target

当我使用运行此服务时C程序文件名的值为“1后服务”和其他参数(“1”,“来自售后服务的参数”)正确传递为参数[1]参数[2]分别。

但是当我使用运行服务时Python或者巴什脚本的值“1后服务”没有效果并打印脚本的主文件名,参数“1”和“Args from after-service”被正确传递为参数[1]参数[2]分别。

对于 python 和 bash 脚本,发生了什么“1后服务”争论?因为如果文件名或 argv[0] 被忽略,我想它应该被传递“1后服务”作为 argv[1] ,其他参数应作为参数[2]参数[3]

这是我编写的c用于打印文件名的代码:

printf("Filename: %s\n",argv[0]);

这是我写的代码python

print(f"Filename:  {sys.argv[0]}")

这是我编写的代码bash

echo Filename $0  

我已经使用符号链接和文件名更改正确测试了这些脚本,所以我猜这仅适用于 C 程序,或者可能是 systemd(版本 251)的错误。

答案1

这里的问题是 shell 进程的进程与shell 脚本内的argv[0]进程不同。$0即使正常启动脚本也可以看到这一点:

$ cat argv0.sh 
#!/bin/sh
echo "Filename $0"
$ sh ./argv0.sh 
Filename ./argv0.sh

shell 会调用诸如execve("/bin/sh", ["sh", "./argv0.sh"], [env vars...])ie argv[0]gets set to之类的内容sh。但是,脚本中的$0名称是脚本运行后,手册页显示:

0
扩展为 shell 或 shell 脚本的名称。这是在 shell 初始化时设置的。如果使用命令文件调用 bash,$0则设置为该文件的名称。”

就该功能而言,名称是什么并不重要口译员被设定为。

我认为这个问题原则上与 Python 类似,例如手册说:

sys.argv
传递给 Python 脚本的命令行参数列表。argv[0]是脚本名称(无论是否是完整路径名,都取决于操作系统)。

然而,Python 3.10 也有sys.orig_argv它看起来可能是你正在寻找的:

sys.orig_argv 传递给 Python 可执行文件的原始命令行参数列表。


如果 shell 以 启动sh -c "code..." arg0 arg1 ...,则代码后的第一个参数将被分配给$0,因此您可以使用它并运行如下所示的代码:

$ sh -c '. ./argv0.sh' foobar
Filename foobar

用于. ./argv0.sh在同一个 shell 中运行脚本,以便它看到相同的内容$0等。

相关内容