0

有时,我碰巧正在执行某些命令,然后才意识到我向命令发送了错误的参数(例如重新启动 Heroku 应用程序)。我想修改 bash,如果它看到包含某个字符串的命令,它会提示我是否确定。例如(想象字符串是 tempus ):

$ heroku restart --app tempus

现在,我希望 bash 使用 Y/N 提示来提示我,如果我键入y,那么我希望它执行命令。如果我键入 N,则不会执行该命令。我该如何处理这个问题?

4

4 回答 4

6

我不知道有什么方法可以拦截所有 bash 命令,但是您可以使用以下技巧拦截预定的命令。

  1. 创建一个目录(比如~/interception)并将其设置为第一个条目$PATH
  2. 在该目录中创建以下脚本,其中包含您希望拦截的命令列表以及实际命令的完整路径

    [bash]$ cat intercept.sh
    #!/bin/bash
    
    # map commands to full path
    declare -A COMMANDS
    COMMANDS[heroku]=/usr/bin/heroku
    COMMANDS[grep]=/bin/grep
    # ... more ...
    
    CMD=$(basename $0)  # command used to call this script
    
    if [[ ! -z "${COMMANDS[$CMD]+x}" ]]; then  # mapping found
      # Do what you wish here. You can even modify/inspect the params.
      echo "intercepted $CMD command... "
    
      ${COMMANDS[$CMD]} $@   # run actual command with all params
    else
      echo "Unknown command $CMD"
    fi
    
  3. 在同一目录中,使用您希望拦截的命令的名称创建指向该脚本的符号链接

    [bash]$ ln -s intercept.sh grep
    [bash]$ ln -s intercept.sh heroku
    

现在,每次调用命令时,都会通过符号链接调用该脚本,然后它可以在调用实际命令之前执行您的出价。

您可以通过$COMMANDS从配置文件中获取并创建辅助命令来进一步扩展此配置文件并创建/删除符号链接。然后,您将能够使用以下命令管理谁设置:

intercept_add `which heroku`
intercept_remove heroku
intercept_list
于 2012-09-27T13:58:30.290 回答
2

因为 bash 本身不支持命令行过滤,所以无法拦截命令。

这是一个肮脏的解决方案:

  1. 查找 PATH 中的所有可执行文件并为每个可执行文件创建包装函数。
  2. 包装函数然后调用prefilter()函数,如果它被声明。
  3. 如果prefilter()函数失败,则取消该命令。

来源:cmd-wrap.sh

#!/bin/bash  # The shebang is only useful for debug. Don't execute this script.

function create_wrapper() {
    local exe="$1"
    local name="${exe##*/}"

    # Only create wrappers for non-builtin commands
    [ `type -t "$name"` = 'file' ] || return

    # echo "Create command wrapper for $exe"
    eval "
    function $name() {\
        if [ \"\$(type -t prefilter)\" = 'function' ]; then \
            prefilter \"$name\" \"\$@\" || return; \
        fi; \
        $exe \"\$@\";
    }"
}
# It's also possible to add pre/post hookers by install
#   [ `type -t \"$name-pre\"` = 'function' ] && \"$name-pre\" \"\$@\"
# into the dynamic generated function body.

function _create_wrappers() {
    local paths="$PATH"
    local path
    local f n

    while [ -n "$paths" ]; do
        path="${paths%%:*}"
        if [ "$path" = "$paths" ]; then
            paths=
        else
            paths="${paths#*:}"
        fi

        # For each path element:
        for f in "$path"/*; do
            if [ -x "$f" ]; then
                # Don't create wrapper for strange command names.
                n="${f##*/}"
                [ -n "${n//[a-zA-Z_-]/}" ] || create_wrapper "$f"
            fi
        done
    done

    unset _create_wrappers  # Remove the installer.
    unset create_wrapper    # Remove the helper fn, which isn't used anymore.
}

_create_wrappers

要将它用于您的问题:

  1. 在 bash 中获取它:

    . ./cmd-wrap.sh
    
  2. 创建您的版本prefilter()以检查是否有任何参数包含该字符串:

    function prefilter() {
        local a y
        for a in "$@"; do
            if [ "$a" != "${a/tempus}" ]; then
                echo -n "WARNING: The command contains tempus. Continue?"
                read y
                [ "$y" = 'Y' ] || [ "$y" = 'y' ]
                return $?
            fi
        done
        return 0
    }
    
  3. heroku restart --app tempus
    

    但不是

    /usr/bin/heroku restart --app tempus
    

    使用包装器功能。

于 2012-09-27T15:23:12.257 回答
2

最简单的方法是使用别名。这个简单的例子应该适合你:

这可以防止在参数中使用 tempus 执行 heroku 命令

function protect_heroku {
    # use grep to determine if the bad string is in arguments
    echo "$*" | grep tempus > /dev/null
    # if string is not in arguments
    if [ $? != 0 ]; then
        # run the protected command using its full path, so as not to trigger alias
        /path/to/heroku "$@"
    else
        # get user confirmation
        echo -n Are you sure \(y/n\)?' '
        read CONFIRM
        if [ "$CONFIRM" = y ]; then
            # run the protected command using its full path
            /path/to/heroku "$@"
        fi
    fi
}

# This is the key:
# This alias command means that 'heroku' from now refers
# to the function protect_heroku, rather than /bin/heroku
alias heroku=protect_heroku

将此代码放入您的 bash 配置文件 ~/.profile,然后注销并重新登录。从现在开始,bash 将保护您免于意外使用 tempus 运行 heroku。

于 2012-09-27T18:09:37.187 回答
1

最简单的方法是替换heroku为在执行真正的heroku 之前进行检查的脚本。另一种方法是为heroku.

于 2012-09-27T13:37:51.813 回答