2

According to the manual man systemd.service using the prefix @ says this:

If the executable path is prefixed with "@", the second specified token will be passed as "argv[0]" to the executed process (instead of the actual filename), followed by the further arguments specified.

But when I run the service with a bash script or python script the filename or argv[0] has no effect. This only works when I use a program written in c language.

Inside my service I have:

[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

When I run this service using a c program the filename takes the value of "after-1-service" and the other arguments ("1","Args from after-service") are passed correctly as argv[1] and argv[2] respectively.

But when I run the service using a python or bash script the value of "after-1-service" has no effect and prints the main filename of the script and the arguments "1" and "Args from after-service" are passed correctly as argv[1] and argv[2] respectively.

In the case of python and bash script what is happening to the "after-1-service" argument? because if the filename or argv[0] is ignored I guess it should be passed the "after-1-service" as argv[1] and the other arguments should be paased as argv[2] and argv[3]

This is my code written in c for printing the filename:

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

This is my code written in python:

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

And this is my code written in bash:

echo Filename $0  

I've tested those scripts using symbolic links and filename changes correctly, so I guess this only works for c programs or maybe it's a bug of systemd (version 251).

0

1 Answer 1

2

The issue here is that the argv[0] of the shell process is not the same as the $0 within the shell script. This can be seen even when starting a script normally:

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

The shell calls something like execve("/bin/sh", ["sh", "./argv0.sh"], [env vars...]), i.e. argv[0] gets set to sh. However, within the script $0 is the name of script that runs, the man page says:

0
Expands to the name of the shell or shell script. This is set at shell initialization. If bash is invoked with a file of commands, $0 is set to the name of that file."

As far as that functionality is concerned doesn't matter what the name of the interpreter is set to.

I assume the issue is similar in principle with Python, and e.g. the manual says:

sys.argv
The list of command line arguments passed to a Python script. argv[0] is the script name (it is operating system dependent whether this is a full pathname or not).

However, Python 3.10 also has sys.orig_argv which looks like it might be what you're looking for:

sys.orig_argv The list of the original command line arguments passed to the Python executable.


If the shell is started with sh -c "code..." arg0 arg1 ... , then the first argument after the code is assigned to $0, so you could use that and run something like this:

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

With . ./argv0.sh used to run the script in the same shell, so that it sees the same $0 etc.

4
  • Thanks for the explanation! I didn't know about that. I had to use without the prefix '@' because it had problems. So I used the sh -c ... code and it worked for bash. In the case of python it seems it doesn't work, what prints is "/bin/python3" as argv[0] and the filename as argv[1]. Commented Aug 21, 2022 at 22:00
  • And why does . ./argv0.sh work and not ./argv0.sh? I understand that . ./argv0.sh is the same as source ./argv0.sh and both run the script (with the some different behavior), but why with source the script takes the arguments and with ./argv0.sh not? Commented Aug 21, 2022 at 22:08
  • 1
    @EdgarMagallon, because if you run ./argv0.sh the shell starts a new shell instance to run the script, first initializing its $0 according to the normal rules, so using the name of the script file. That wouldn't help in making the script see the manually-set $0. With . scriptfile, no new shell is started, but it's (almost) the same as if we ran sh -c 'echo "Filename $0"' foobar directly.
    – ilkkachu
    Commented Aug 21, 2022 at 23:12
  • Thank you again! Those are really good examples :). Commented Aug 21, 2022 at 23:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .