代码之家  ›  专栏  ›  技术社区  ›  bstpierre Edgar Aviles

如何在bash中更改argv0,以便命令在ps中以不同的名称出现?

  •  22
  • bstpierre Edgar Aviles  · 技术社区  · 14 年前

    在C程序中,我可以编写argv[0],新名称会显示在ps列表中。

    在Bash中我怎么做?

    7 回复  |  直到 6 年前
        1
  •  26
  •   Ignacio Vazquez-Abrams    14 年前

    您可以在运行新程序时通过 exec -a <newname> .

        2
  •  9
  •   bstpierre Edgar Aviles    14 年前

    我有机会浏览一下bash的源代码,它看起来不支持写入argv[0]。

        3
  •  9
  •   Vincent Fourmond    10 年前

    只是为了记录,尽管它不能准确回答原始海报的问题,但这与 zsh :

    ARGV0=emacs nethack
    
        4
  •  6
  •   joe    14 年前
    ( exec -a foo bash -c 'echo $0' ) 
    
        5
  •  6
  •   Patrick    6 年前

    我假设您有一个shell脚本希望执行,这样脚本进程本身就有了一个新的 argv[0] . 例如(我只在bash中测试过这个,所以我正在使用它,但这在其他地方也可以使用)。

    #!/bin/bash
    
    echo "process $$ here, first arg was $1"
    ps -p $$
    

    输出如下:

    $ ./script arg1
    process 70637 here, first arg was arg1
      PID TTY           TIME CMD
    70637 ttys003    0:00.00 /bin/bash ./script arg1
    

    所以 ps 显示外壳, /bin/bash 在这种情况下。现在试试你的互动外壳 exec -a 但是在子shell中,这样您就不会吹走交互式shell:

    $ (exec -a MyScript ./script arg1)
    process 70936 here, first arg was arg1
      PID TTY           TIME CMD
    70936 ttys008    0:00.00 /bin/bash /path/to/script arg1
    

    汪汪,还在显示 /BI/BASH . 发生了什么事?这个 执行程序-A 可能是布景 AGV〔0〕 ,但随后启动了一个新的bash实例,因为操作系统读取了 #!/bin/bash 在脚本的顶部。好吧,如果我们以某种方式执行脚本中的执行呢?首先,我们需要某种方法来检测这是脚本的“第一次”执行,还是第二次执行, exec ED实例,否则第二个实例将再次执行,并在无限循环中持续执行。接下来,我们需要可执行文件 作为一个文件 哎呀!/BI/BASH 顶部的行,以防止操作系统更改所需的argv[0]。这是我的尝试:

    $ cat ./script
    #!/bin/bash
    
    __second_instance="__second_instance_$$"
    [[ -z ${!__second_instance} ]] && {
      declare -x "__second_instance_$$=true"
      exec -a MyScript "$SHELL" "$0" "$@"
    }
    
    echo "process $$ here, first arg was $1"
    ps -p $$
    

    多亏了 this answer ,我首先测试环境变量 __second_instance_$$ 根据PID(不会改变 执行程序 )这样它就不会与使用此技术的其他脚本发生冲突。如果它是空的,我假设这是第一个实例,然后导出该环境变量,然后执行。但是,重要的是,我不执行这个脚本,而是直接执行shell二进制文件,使用这个脚本( $0 )作为一个论点,传递所有其他论点( $@ )环境变量有点像黑客。

    现在的输出是:

    $ ./script arg1
    process 71143 here, first arg was arg1
      PID TTY           TIME CMD
    71143 ttys008    0:00.01 MyScript ./script arg1
    

    就快到了。这个 AGV〔0〕 MyScript 就像我想要的,但还有一个额外的参数 ./script 这是直接执行shell的结果(而不是通过操作系统的 #! 加工)。不幸的是,我不知道该如何做得更好。

    bash 5.0的更新

    看起来bash 5.0增加了对特殊变量的写入支持 BASH_ARGV0 因此,这应该变得简单得多。

    (见 release announcement )

        6
  •  0
  •   Omnifarious    7 年前

    我只想补充一点,至少在某些环境中,这在运行时是可能的。在Linux上的Perl中分配$0确实改变了在ps中显示的内容,但是我不知道如何实现。如果我能找到答案,我会更新这个。

    <编辑>: 基于Perl的工作方式,这是非常重要的。我怀疑运行时是否有任何bask内置的方式,但不确定。您可以看到perl如何在运行时设置进程名。

    D出,我会更新这个。

    编辑: 基于Perl的工作方式,这是非常重要的。我怀疑运行时是否有任何bask内置的方式,但不确定。你可以看到 Perl如何在运行时设置进程名 .

        7
  •  -1
  •   teknopaul    7 年前

    将bash可执行文件复制到其他名称。

    您可以在脚本本身中执行此操作…

    cp /bin/bash ./new-name
    PATH=$PATH:.
    exec new-name $0
    

    如果您试图假装自己不是shell脚本,则可以将脚本本身重命名为酷的内容,甚至可以将其重命名为“”(单个空间),因此

    exec new-name " "
    

    将执行bash脚本并显示在ps列表中 new-name .

    好吧,所以调用脚本“”是一个非常糟糕的主意:)

    基本上,更改名称

    bash script
    

    重命名bash并重命名脚本。

    如果你担心的话,就像麦克唐纳先生。显然,关于将二进制文件复制到新名称(这是完全安全的),您还可以创建一个符号链接

    ln -s /bin/bash ./MyFunkyName
    ./MyFunkyName
    

    这样,符号链接就出现在ps列表中。(再次使用path=$path:。如果你不想要。/)