6

I remember many years (decades) ago using a system where one could say something like:

$ realname:newname A B C

and the program would be invoked with argv = { "newname", "A", "B", "C" }.

I don't remember what shell this was though.

Does such a capability exist in any current shells?

UPDATE:

exec -a looked like it was what I wanted, but I'm getting inconsistent behaviour depending upon the program's language (yes, I know it's awful code):

$ cat argv.c  && cc argv.c
int main(int argc, char **argv) { printf("<< %s >>\n", argv[0]); }

$ (exec -a fake ./a.out)
<< fake >>

It works fine in "C", but not in python:

$ cat argv.py
#!/usr/bin/python3
import sys
print("<<", sys.argv[0], ">>")

$ (exec -a fake ./argv.py)
<< /home/ray/test/argv.py >>
1
  • just to be clear, though it's already said in some answers but your python version works as expected. you want sys.argv[1] instead Commented Mar 23, 2024 at 10:21

5 Answers 5

10

With zsh (since the first release in 1990):

$ ARGV0="new value for ps's argv[0]" ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
stephane   45193    2195  0 12:08 pts/11   00:00:00 /bin/zsh
stephane   45510   45193  0 12:15 pts/11   00:00:00 new value for ps's argv[0] -f

zsh also has a - builtin to start a command with - prepended to argv[0] (as used to start shells as login shells):

$ - ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
stephane    2221    2195  0 06:21 pts/4    00:00:01 /bin/zsh
stephane   46537    2221  0 12:42 pts/4    00:00:00 -ps -f

ksh (since 1993), bash (since 2.0 in 1996), zsh (since 4.3.5 in 2008), bosh (since the 2015-08-27 release), mksh (since R52c in 2016), busybox ash (since 1.27.0 (2017)) at least:

$ (exec -a "new value for ps's argv[0]" ps -f)
UID          PID    PPID  C STIME TTY          TIME CMD
stephane    2221    2195  0 06:21 pts/4    00:00:01 /bin/zsh
stephane   46558    2221  0 12:43 pts/4    00:00:00 new value for ps's argv[0] -f

With perl:

$ perl -e 'exec {shift} @ARGV' /bin/ps "new value for ps's argv[0]" -f
UID          PID    PPID  C STIME TTY          TIME CMD
stephane   46585    2195  0 12:44 pts/14   00:00:00 /bin/zsh
stephane   46646   46585  0 12:45 pts/14   00:00:00 new value for ps's argv[0] -f

With python:

$ python3 -c 'import os; import sys; os.execvp(sys.argv[1], sys.argv[2:])' ps "new value for ps's argv[0]" -f 
UID          PID    PPID  C STIME TTY          TIME CMD
stephane   46585    2195  0 12:44 pts/14   00:00:00 /bin/zsh
stephane   46985   46585  0 12:53 pts/14   00:00:00 new value for ps's argv[0] -f

But beware that when you execute a script (with the execve() system call) that starts with:

#! /path/to/interpreter optional-arg

as shebang as:

execve("/path/to/script", ["arg0", "arg1", ...], env)

The system transforms it to:

execve("/path/to/interpreter", [something, "optional-arg", "/path/to/script", "arg1", ...], env)

With something being, depending on the system either /path/to/interpreter or argv0 (the former on Linux).

And interpreters, when exposing arg lists in their API, expose the argument list of the script, not of the interpreter, so $0 / sys.argv[0] will not be something above, but /path/to/script.

1
  • What a great, comprehensive answer on just about everything relevant. Commented Oct 22, 2021 at 6:49
4

When starting a shell using its -c option to run an in-line script, the first argument will be placed in $0:

$ sh -c 'printf "0: %s\n" "$0"; printf "Other: %s\n" "$@"'  hello there how are you
0: hello
Other: there
Other: how
Other: are
Other: you

In bash, assigning to BASH_ARGV0 changes the current shell's $0 value:

$ printf '%s\n' "$0"
/usr/local/bin/bash
$ BASH_ARGV0="hello"
$ printf '%s\n' "$0"
hello

(but it does not change the process' name on my system)

Using set, you'd change the other arguments:

$ printf '%s\n' "$@"

$ set -- A B C
$ printf '%s\n' "$@"
A
B
C
1

A symlink maybe enought for most systems:

~$ cat test.c 
#include <stdio.h>

int main(int ac, char **av)
{
    printf("%s\n", av[0]);
}
~$ cc -o test test.c
~$ ./test 
./test
~$ ln -s test coincoin 
~$ ./coincoin 
./coincoin

This is the mechanism used by busybox (widely used in embedded systems) to implement several utilities (ping, route, etc...) using only one binary.

1
  • 3
    Also common on many systems to do similar things. On OpenBSD, for example, the cksum, md5, sha1, sha256 and sha512 utilities are all the same file with different names (hard links). Commented Jan 16, 2020 at 15:13
0

[not a real answer yet]

When used with a she-banged executable script, neither

execl("/path/to/script", "new_av0", (void*)0)

in C, nor

exec -a new_av0 /path/to/script

in shells which support exec -a will be able to set $0 or sys.argv[0] (or whatever language syntax is used to refer to the zeroth argument) in that script.

When executing the interpreter of a she-banged script, the kernel will irretrievably discard the original zeroth argument, splicing in its place the name of the interpreter, any optional she-bang line argument, and the path to the script.

Any solution is bound to be tricky, limited or language/system dependent.

For instance, a shell script could be fooled with:

sh -c '. /path/to/script' new_av0

But obviously, this will not affect the command line as it appears in the output of ps, /proc/<pid>/cmdline, /proc/<pid>/comm etc.

0

For completeness, I see that FreeBSD ports has the argv0 command since around version 7.1 (2009)

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.