从命令行更改 argv

从命令行更改 argv

我记得很多年(几十年)前使用过一个系统,人们可以这样说:

$ realname:newname A B C

并且该程序将被调用argv = { "newname", "A", "B", "C" }

不过我不记得这是什么壳了。

当前的 shell 中是否存在这种功能?

更新:

exec -a看起来这就是我想要的,但根据程序的语言,我得到了不一致的行为(是的,我知道这是糟糕的代码):

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

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

它在“C”中运行良好,但在 python 中则不然:

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

$ (exec -a fake ./argv.py)
<< /home/ray/test/argv.py >>

答案1

zsh(自 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还有一个-内置命令可以启动一个-前置命令argv[0](用于将 shell 作为登录 shell 启动):

$ - 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(自 1993 年起)、bash(自 1996 年 2.0 起)、桀骜(自 2008 年 4.3.5 起)、bosh(自 2015-08-27 版本起)、mksh(自 2016 年 R52c 起)、busybox ash(自 1.27.0 (2017) 起)至少:

$ (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

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

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

execve()但请注意,当您执行以以下内容开头的脚本(使用系统调用)时:

#! /path/to/interpreter optional-arg

作为舍邦:

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

系统将其转换为:

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

随着something存在,取决于系统或(Linux 上/path/to/interpreterargv0前者)。

解释器在其 API 中公开 arg 列表时,会公开参数列表脚本的, 不是口译员的,所以$0/sys.argv[0]不会在something上面,但是/path/to/script.

答案2

当使用其选项启动 shell-c来运行内联脚本时,第一个参数将放置在$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

在 中bash,分配 toBASH_ARGV0会更改当前 shell 的$0值:

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

(但它不会更改我系统上的进程名称)

使用set,您可以更改其他参数:

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

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

答案3

对于大多数系统来说,符号链接可能就足够了:

~$ 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

这是一种机制busybox(广泛用于嵌入式系统)仅使用一个二进制文件来实现多个实用程序(ping、路由等)。

答案4

为了完整起见,我看到 FreeBSD portsargv0从版本 7.1 (2009) 开始就有这个命令

相关内容