使用 os/exec 或 golang.org/x/sys/unix 包执行命令时, 我们如何执行更改命令名称 argv0 的命令,如
exec
的 -a
选项?
例如
exec -a assumego granted "$@" # Execute granted as assumego
我希望我们可以通过更改
exec.Cmd.Args[0]
或 unix.Exec's argv[0]
来更改命令名称,但它们不起作用。
脚本
foo
:
#!/usr/bin/env bash
set -eu
echo "0: $0"
echo "@: $@"
echo foo
main.go 使用 os/exec:
package main
import (
"log"
"os"
"os/exec"
)
func main() {
if err := core(); err != nil {
log.Fatal(err)
}
}
func core() error {
cmd := exec.Command("./foo", "a", "b")
cmd.Args[0] = "bar"
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}
return nil
}
运行main.go,但$0没有改变。
$ go run main.go
0: ./foo
@: a b
foo
main.go 使用 golang.org/x/sys/unix:
package main
import (
"log"
"os"
"golang.org/x/sys/unix"
)
func main() {
if err := core(); err != nil {
log.Fatal(err)
}
}
func core() error {
return unix.Exec("../foo", []string{"bar", "a", "b"}, os.Environ()) //nolint:wrapcheck
}
运行main.go,但$0没有改变。
$ go run main.go
0: ../foo
@: a b
foo
参考:
背景:
我不确定它是什么时候引入的,但是在当前版本的 bash 中,您可以设置/导出
BASH_ARGV0
。 https://www.man7.org/linux/man-pages/man1/bash.1.html
但是,如果您需要支持旧版本的 bash,例如 Mac 上的 3.2 版本,则此功能不可用。
Zsh 允许直接设置
0
。 Posix shell 没有执行此操作的方法。
我(现在已经多次)使用过一个“黑客”来解决这个问题,它可以与 shell 脚本以及可执行文件一起使用,它是使用我想要的名称作为 argv[0] 创建符号链接。
bash-3.2$ echo -e '#!/bin/sh\necho "$(basename "$0")" "$@"' >tmp.sh \
&& chmod +x tmp.sh \
&& ./tmp.sh hello world \
&& ln -s tmp.sh foo \
&& ./foo hello world
tmp.sh hello world
foo hello world
这允许很多有趣的模式,例如可以重定向到其他可执行文件的“调度”可执行文件。根据用例,这些符号链接也可以按需创建并在执行后清理。