22

In bash you can use exec -a and in zsh you can alternatively also set ARGV0 to execute a program with a certain zeroth argument but is there also a POSIX way of doing so?

As suggested in this one comment you could create a (temporary) symbolic link to achieve this but this way I couldn't set the new zeroth argument value to truly any arbitrary value, e.g. the command with a certain absolute path. So is there any other solution?

0

2 Answers 2

28

No, there's no POSIX way, other than compiling a C program that does it. As a quick and dirty one:

$ echo 'int main(int c,char*v[]){
  execvp(v[1],&v[2]);perror(v[1]);return 127;}'>r.c && make r
$ ./r ps zzz -f
UID        PID  PPID  C STIME TTY          TIME CMD
chazelas  7412  7411  0 10:44 pts/4    00:00:00 /bin/zsh
chazelas 21187  7412  0 22:33 pts/4    00:00:00 zzz -f

exec -a is supported by ksh93, bash, zsh, busybox ash (since version 1.27.0), yash, mksh (since version r50e), the Schily Bourne Shell (since August 2015) so is the most widespread among shells.

Probably the most portable would be to resort to perl which is more likely to be available than a C compiler.

$ perl -e 'exec {shift} @ARGV' ps zzz -f
UID        PID  PPID  C STIME TTY          TIME CMD
chazelas  7554  7411  0 10:58 pts/12   00:00:00 /bin/zsh
chazelas  7630  7554  0 11:02 pts/12   00:00:00 zzz -f
15

For completeness, here are some C and C++ programs for doing this that people have already compiled.

Going by the commentary that you point to, your apparent motivation for asking for "a POSIX way" of doing this is to know how one can achieve this same end with shells such as the Debian Almquist shell, the MirBSD Korn shell (before version R50e), the Debian POSIX-Compliant Ordinary shell, and other shells that do not have extensions for setting the 0th argument as the Bourne Again and Z shells have. (The '93 Korn shell, and the MirBSD Korn shell from version R50e onwards, support an -a option to their built-in exec commands.)

execline

Laurent Bercot's execline comes with an exec command. So to duplicate M. Chazelas' example one would have an execline script such as

#!/command/execlineb -P
exec -a zzz ps -f

Bercot's exec is an ordinary external command, of course. So one could run it from within a Debian Almquist Shell script. To overlay the current shell program one would use the shell's exec to overlay with Bercot exec, which in turn would set the 0th argument and overlay with the target program:

exec /command/exec -a "$argv0" printer.sh

nosh

The nosh toolset includes an exec command. To duplicate M. Chazelas' example one would have a nosh script such as

#!/bin/nosh
exec -a zzz ps -f

Although it is a nosh built-in, this exec is also accessible as an ordinary external command. So one could run it from within a Debian Almquist Shell script. To overlay the current shell program one would use the shell's exec to overlay with the nosh toolset's exec, which in turn would set the 0th argument and overlay with the target program:

exec /usr/local/bin/exec -a "$argv0" printer.sh

perp

Wayne Marshall's perp includes a runargv0 command. This is an ordinary external command. So one could run it from within a Debian Almquist Shell script. To overlay the current shell program one would use the shell's exec to overlay with the perp toolset's runargv0, which in turn would set the 0th argument and overlay with the target program:

exec runargv0 printer.sh "$argv0"

runit

Gerrit Pape's runit includes a chpst command. This is an ordinary external command. So one could run it from within a Debian Almquist Shell script. To overlay the current shell program one would use the shell's exec to overlay with runit's chpst, which in turn would set the 0th argument and overlay with the target program:

exec chpst -b "$argv0" printer.sh

ucspi-tcp

Daniel J. Bernstein's ucspi-tcp includes an argv0 command. (argv0 is also available in djbwares.) This is an ordinary external command. So one could run it from within a Debian Almquist Shell script. To overlay the current shell program one would use the shell's exec to overlay with ucspi-tcp's argv0, which in turn would set the 0th argument and overlay with the target program:

exec argv0 printer.sh "$argv0"

3
  • 1
    As a refugee from runit reluctantly turned to systemd, I'm very glad to be introduced to nosh. Many thanks! Dec 21, 2015 at 19:06
  • With a printer.sh executable script which looks like #! /bin/sh, newline, printf 'av0={%s}\n' "$0", will any of those programs be able to make it print something else than av0={/path/to/printer.sh}?
    – user313992
    Jan 17, 2020 at 14:58
  • Fortunately, the question only asks how to set the argument, like the shells do, not how to cope with it being replaced by something else afterwards. (-: As both answers here say, there's a quite conformant way of doing that. This answer points out that the C and C++ programs have already been written and compiled. They've even been packaged for several operating systems in some cases.
    – JdeBP
    Jan 17, 2020 at 21:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.