如何拦截包含某个字符串的命令?

时间:2012-09-27 13:30:02

标签: bash

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

$ heroku restart --app tempus

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

4 个答案:

答案 0 :(得分:3)

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

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

    [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
    
  4. 在同一目录中,使用您要拦截的命令名称为该脚本创建符号链接

    [bash]$ ln -s intercept.sh grep
    [bash]$ ln -s intercept.sh heroku
    
  5. 现在,每次调用该命令时,都会通过符号链接调用该脚本,然后它可以在调用实际命令之前进行出价。

    您可以通过从配置文件中获取$COMMANDS来进一步扩展它,并创建帮助程序命令以扩充配置文件并创建/删除sym链接。然后,您可以使用以下命令管理who设置:

    intercept_add `which heroku`
    intercept_remove heroku
    intercept_list
    

答案 1 :(得分:2)

由于bash本身不支持命令行过滤器,因此无法拦截命令。

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

  1. 在PATH中查找所有可执行文件,并为每个可执行文件创建包装函数。
  2. 如果已声明,则包装函数会调用prefilter()函数。
  3. 如果prefilter()功能失败,则取消该命令。
  4. 消息来源: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
      

      使用包装函数。

答案 2 :(得分: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。

答案 3 :(得分:1)

最简单的方法是在执行真正的heroku之前用执行检查的脚本替换heroku。另一种方法是为heroku添加bash别名。