4

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 >>
Ray Butterworth
  • 426
  • 1
  • 5
  • 14

4 Answers4

3

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
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
3

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.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
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.

binarym
  • 2,639
  • 9
  • 12
  • 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). – Kusalananda Jan 16 '20 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.