需要一种优雅的方式来重载由另一个工具动态创建和调用的 Bash 脚本中的命令

Need an elegant way to overload a command in a Bash script dynamically created and called by another tool

有很多关于如何在 Bash 中重载命令的帖子,要么通过创建别名或函数,要么只更改脚本本身或如何调用它;这些方法对我来说非常有意义,但不适用于我要解决的问题。

在半导体行业中,使用在 Tcl 解释器中提供 API 命令的 EDA 工具是很常见的;在我的例子中,EDA 工具生成一个 Bash 脚本,然后执行一个 API 调用,所以我只能在脚本执行后访问脚本并且不能修改它的调用方式,因为它发生在兜帽;也没有用于修改写入脚本的感兴趣命令的好方法。

更复杂的是,这个脚本是由 Singularity 容器内的 EDA 工具生成和调用的;此外,被调用的命令驻留在不同的 EDA 工具容器中,因此此命令 'vsim' 必须转换为对我们的工作负载管理器 (slurm) 的 ssh 调用。例子: vsim <args> 必须转换为: ssh <some-host> <ssh-options> "srun <srun-options> vsim <args>"

同样,在父 shell 中设置一个名为 'vsim' 的别名或函数对我不起作用; alias/function 没有被子进程继承(这让我很难接受)。我还尝试创建一个名为 'vlog' 的符号链接,它指向一个静态调度程序脚本;这是通过我宁愿不将调度程序的路径硬编码为文件路径来实现的;我宁愿使用变量,例如 vlog -> .../<resource>/$VERSION/bin/dispatch_for_flows,但符号链接不是动态的。

我认为我仍然应该使用符号链接方法,但我不会指向调度程序,而是指向一个包装器,该包装器对调度程序的内插路径执行单行执行,但我仍然不相信设置别名不能解决问题。多年来,我编写了带有完整命令路径的 Csh 脚本来绕过用户别名;使用 Bash,看起来别名从未被继承,即使在父 shell 或什至 /etc/profile 中打开了 shopt 'expanand_alias'。我在这里错过了什么?

有人能让下面的例子起作用吗?我希望脚本从父 shell 继承别名并在没有 "command not found" 错误的情况下执行,而不修改脚本或调用它的方式。同样,在脚本执行之前我无权访问它,也无法控制它的调用方式; bash 是父 shell,bash 是脚本,我在 OS 上有 root 访问权限,所以如果需要我可以更改 bash 的版本(使用 4.4.19(1)-release (x86_64-redhat-linux-gnu))

$ alias hello='echo world'
$ hello
world
$ shopt | grep expand_aliases
expand_aliases  on
$ cat test.bash
#!/usr/bin/bash
set -x
alias
shopt | grep expand_aliases
shopt -s expand_aliases
shopt | grep expand_aliases
hello

$ ./test.bash
+ alias
+ shopt
+ grep expand_aliases
expand_aliases  off
+ shopt -s expand_aliases
+ shopt
+ grep expand_aliases
expand_aliases  on
+ hello
./test.bash: line 7: hello: command not found

Can someone get the example below to work?

不,别名无法做到这一点 - 您无法导出别名。但是你可以导出一个函数。

$ hello() { echo world; }
$ export -f hello
$ ./test.bash
world

您可以在 PATH 中创建自定义命令:

$ printf "%s\n" "#!/bin/bash" "echo world" > /usr/local/bin/hello
$ chmod +x /usr/local/bin/hello

并类似地添加自定义命令并使用该命令添加新路径到 PATH 并导出。