在执行之前通过程序修改所有 bash 命令

在执行之前通过程序修改所有 bash 命令

我正在尝试创建一个需要此类功能的程序。流程如下:

  • 用户输入 bash 命令
  • 用户按下回车键
  • 我的脚本将获取命令、当前目录...作为变量。程序可以选择修改命令。
  • 修改后的命令将正常执行。

有什么办法可以做到这一点吗?

注意:我需要这个供我个人使用,我不会分发这个程序。

答案1

我对此做了一些研究。我们可以使用 bashTRAPshoptoption 来实现这一点。

将其添加到 .bash_profile

shopt -s extdebug

preexec_invoke_exec () {
    [ -n "$COMP_LINE" ] && return  # do nothing if completing
    [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
    local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`;

    # So that you don't get locked accidentally
    if [ "shopt -u extdebug" == "$this_command" ]; then
        return 0
    fi

    # Modify $this_command and then execute it
    return 1 # This prevent executing of original command
}
trap 'preexec_invoke_exec' DEBUG

它的工作原理如下:

trap 'function_name' DEBUG导致function_name在执行 bash 命令之前执行。但默认return值对原始命令没有影响。

shopt -s extdebug启用一些调试功能,其中之一在执行原始命令之前检查返回值。

注意:shopt -u extdebug禁用此功能,以便始终执行原始命令。

文档extdebug(参见第二个功能):

If set, behavior intended for use by debuggers is enabled:

The -F option to the declare builtin (see Bash Builtins) displays the source file name and line number corresponding to each function name supplied as an argument.
If the command run by the DEBUG trap returns a non-zero value, the next command is skipped and not executed.
If the command run by the DEBUG trap returns a value of 2, and the shell is executing in a subroutine (a shell function or a shell script executed by the . or source builtins), a call to return is simulated.
BASH_ARGC and BASH_ARGV are updated as described in their descriptions (see Bash Variables).
Function tracing is enabled: command substitution, shell functions, and subshells invoked with ( command ) inherit the DEBUG and RETURN traps.
Error tracing is enabled: command substitution, shell functions, and subshells invoked with ( command ) inherit the ERR trap.

答案2

您可以通过一个简单的 bash 脚本来实现您的目标,该脚本使用内置的 readline 系统来获取一行。例如:

#!/bin/bash -i
while read -e -p '$ ' line
do    echo "your cmd: $line"
      eval "$line"
done

该脚本使用 readline 编辑 (-e) 读取一行输入(除非文件结尾),然后回显并执行它。请注意-i上的#!以确保脚本是交互式的。您可以基于此构建代码来操作输入命令。例如,

#!/bin/bash -i

myfn(){
  echo "in dir $1. doing: $2" >&2
  echo "$2" # manipulate command here and echo the result
}

while read -e -p "$PS1" line
do    newcmd=$(myfn "$PWD" "$line")
      eval "$newcmd"
done

答案3

安装bash-preexec - Bash 的 preexec 和 precmd 函数,就像 Zsh 一样

两个功能预执行预命令现在可以定义它们,如果它们存在,它们将被 bash-preexec 自动调用。

  • preexec在读取命令并即将执行后立即执行。用户键入的字符串作为第一个参数传递。
  • precmd在每个提示之前执行。相当于PROMPT_COMMAND,但更加灵活和有弹性。

source ~/.bash-preexec.sh
preexec() { echo "just typed $1"; }
precmd() { echo "printing the prompt"; }

应该输出类似:

elementz@Kashmir:~/git/bash-preexec (master)$ ls
just typed ls
bash-preexec.sh  README.md  test
printing the prompt

您还可以通过将函数附加到两个不同的数组来定义要调用的函数。如果您想为任一钩子调用许多函数,这非常有用。

答案4

在任何 shell 脚本中,当前执行的命令都可以作为$0,并且可以通过调用 轻松检索当前目录pwd。为了执行您想要的操作,您必须编写一个可以用作 shell 的程序,然后将用户的 shell 值设置为该程序。

相关内容