Bash 完成脚本 - 获得类似 "transparent proxy" 的行为

Bash completion scripting - getting a "transparent proxy"-like behaviour

我正在尝试为 运行 将其参数作为命令的程序编写一个简单的 Bash 完成脚本。一个很好的例子是 nvidia-prime 包提供的 prime-run 脚本:

#!/bin/bash
__NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia "$@"

这个脚本设置了一些环境变量,指示主要驱动程序在混合系统上使用 Nvidia dGPU。第一个参数被视为命令,所有尾随参数都被传递。因此,例如您可以 运行 prime-run code . 并且 VSCode 将使用 dGPU 在当前目录中启动。

因此,从完成脚本 POV 来看,我们想要的是基本上尝试完成,就好像 prime-run 令牌不存在一样(因此“透明代理”行为)。举一个相当人为的例子:

> prime-run journalc<TAB>
(completes journalctl)
> prime-run journalctl --us<TAB>
(completes --user)

但是我发现这在 Bash 中非常困难(我不知道在其他 shell 中如何)。所以问题很简单:是否可能,如果可能如何?

我(绝望地)有过的想法

TL;DR

bash-completion提供了一个名为_command_offset(permalink)的函数,正是我需要的

# A meta-command completion function for commands like sudo(8), which need to
# first complete on a command, then complete according to that command's own
# completion definition.

如果您对我如何来到这里感兴趣,请继续阅读。


所以前几天我在做白日梦,当它击中我时 - sudo 基本上没有我想要的完全相同的行为吗?因此任务变得简单 - 对 sudo 的完成脚本进行逆向工程。此处提供来源:permalink.

事实证明,大部分代码都与完成各种选项有关,因此简单地将大部分代码扔掉是安全的:

  • L 8-11、50-52:与sudo的编辑模式有关。可以安全地开沟。
  • L 19-24、27-39、43-49:这些完成了 sudo 的选项。可以安全地开沟。

所以我们剩下这个:

_sudo()
{
    local cur prev words cword split
    _init_completion -s || return

    for ((i = 1; i <= cword; i++)); do
        if [[ ${words[i]} != -* ]]; then
            local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
            local root_command=${words[i]}
            _command_offset $i
            return
        fi
    done

    $split && return
} &&
    complete -F _sudo sudo sudoedit
  • forif 块用于处理“来宾命令”之前的 sudo 选项。可以安全地放弃(在将所有 $i 替换为 1 之后)。
  • 变量$split只在_init_completion(permalink)中被引用,似乎是用来处理不同的参数样式(--foo=barv.s.--foo bar).与 -s 标志相同。无关紧要。
  • 附加到$PATH和设置$root_command与权限升级有关。仅与 sudo.
  • 有关

所以在尘埃落定之后,通过排除过程,我得到了这个简单的代码块:

_my-script()
{
    local cur prev words cword
    _init_completion || return

    _command_offset 1

} && complete -F _my-script my-script

声明这四个局部变量并调用 _init_completion 是所有完成脚本的标准,所以实际上它就像一个命令一样简单。当然有人必须编写 massively-complex _command_offset 函数,我猜我很幸运吧?

无论如何,感谢你阅读我的胡闹故事,希望这对以后的其他人有所帮助。