如何在执行前使用自定义命令自动包装 Zsh/Bash 中的每个命令?

如何在执行前使用自定义命令自动包装 Zsh/Bash 中的每个命令?

Zsh我正在尝试修改(或) shell的行为,以在执行之前Bash自动在所有输入中添加一个自定义命令(例如命名) 。myapp本质上,我想拦截并修改用户的输入,当他们按下 时ENTER_KEY,应该执行修改后的命令。

我在 shell 中输入的任何命令,例如:

grep -rn hello

应该像我输入一样进行处理

$ myapp grep -rn hello

另一个例子,如果我输入ls,它应该被执行为myapp ls

目标

我想尝试使用 vim 自动作为某些 cli 工具的查看器:

# myapp
vim -c "term $*"

答案1

考虑到目标,最简单的解决方案是将命令的结果通过管道传递给 vim,如下所示。

$ yourcommand | vim -

例如,

$ grep -rn hello | vim -

答案2

我假设您想要进入和退出这种安排,因此我做了以下操作。对于 zsh,DEBUG 陷阱处理程序可以通过设置 ERR_EXIT 选项来跳过已提交命令的执行,而是运行您的自定义命令

# this is run before every command
debug_trap() {
    # get last submitted command
    cmd="${history[$HISTCMD]}";
    if [ "$cmd" ]; then
        # catch the unwrap command and remove the trap
        if [ "$cmd" = "unwrap" ]; then
            print 'Unwrapping command-line';
            trap - DEBUG;
            return;
        fi
        # make sure multiple trap triggers only handle this once
        if [ "$handled" != "$HISTCMD;$cmd" ]; then
            # when either history index or command text
            # changes, we can assume its a new command
            handled="$HISTCMD;$cmd";
            # do whatever with $cmd
            myapp $cmd;
        fi
        # optionally skip the raw execution
        setopt ERR_EXIT;
    fi
}

# start the debug trap
wrap() {
    print 'Wrapping command-line';
    trap 'debug_trap' DEBUG;
}

# this is just defined in order to avoid errors
# the unwrapping happens in the trap handler
unwrap() {}

bash 中的等效内容:

# bash requires this option in order to skip execution
# inside the debug trap
shopt -s extdebug;

# this is run before every command
debug_trap() {
    cmd="$BASH_COMMAND";
    # catch the unwrap command and remove the trap
    # notice how the alias is expanded here and
    # the command is no longer 'unwrap'
    if [[ "$cmd" == 'trap - DEBUG' ]]; then
        echo 'Unwrapping command-line';
        # the trap is unset by the submitted command
    else
        # do whatever with $cmd
        myapp $cmd;
        # optionally skip the raw execution
        return 1;
    fi
}

# start the debug trap
wrap() {
    echo 'Wrapping command-line';
    trap debug_trap DEBUG;
}

# we can't unset global traps inside a function
# so we use an alias instead
alias unwrap='trap - DEBUG';

使用示例:

> myapp() { echo "### $1"; }
> wrap
Wrapping command-line
> echo 123
### echo 123
> unwrap
Unwrapping command-line
> echo 123
123

要实现 vim 功能,请相应地在 myapp 函数中使用“vim -c”或更改“myapp $cmd;” trap 函数中的行。

然而,使用前的警告。调试陷阱非常挑剔,我尝试使用 zsh 版本来减少错误。使用像 oh-my-*sh 这样的插件可能会引入钩子、陷阱和其他机制,从而大大增加实现稳定实现的难度。 zsh 版本针对 oh-my-zsh 进行了测试,应该可以工作。 bash 版本仅在没有修饰的 bash v4.2 上进行了测试。

zsh 中的其他潜在实现:您可以覆盖绑定到返回键的默认 zle 小部件“accept-line”,该返回键可以在提交执行之前操作您的文本缓冲区,这可能是一个更干净的解决方案。还有“preexec”挂钩函数可能很有用,但它似乎没有自行更改或跳过命令的方法。

其他使用思路:您可以使用它来将命令发送(ssh)到一台或多台远程计算机,将它们写入脚本文件并推迟执行,在执行前进行静态分析,要求确认或要求修复拼写错误。

相关内容