Bash/Zsh:捕获所有以“/”开头的命令

Bash/Zsh:捕获所有以“/”开头的命令

有没有办法让这个示例catchall函数在交互式 shell 中以字符开头的任何命令被调用/(而不是搜索$PATH并执行其他命令等)?

例如,我想要

/arg1 arg2 arg3

打电话

function catchall() {
    /* $1 == "arg1"
       $2 == "arg2"
       $3 == "arg3" */
    ...
}

答案1

针对 Bash 的有限(不完美)解决方案:

shopt -s extdebug

_generic() {
   case "$BASH_COMMAND" in
      /* )
         eval "_specific $BASH_COMMAND"
         return 1
      ;;
   esac
}

_specific() {
   printf "Got arguments: "
   printf '<%s> ' "$@"
   printf '\n'
   printf 'The command was: %s\n' "$BASH_COMMAND"
}

trap '_generic' DEBUG

根据:

使用示例:

$ /foo "a         b" /dev/[nf]ul* ; /bar <(cat)
Got arguments: </foo> <a         b> </dev/full> </dev/null> 
The command was: /foo "a         b" /dev/[nf]ul*
Got arguments: </bar> </dev/fd/63> 
The command was: /bar <(cat)
$ 

笔记:

  • 我不了解 Zsh。这个答案适用于 Bash。

  • eval可能是邪恶的。据我所知,evaluating$BASH_COMMAND并没有错,因为$BASH_COMMAND它相当于您输入的字符串,并且尚未被评估。eval无论如何,我们的操作都是 shell 通常会执行的操作。

  • 仍然$BASH_COMMAND不是您输入的完整字符串。例如/foo; /bar将调用_generic(因此_specific分别地对于/foo/bar。这就是DEBUG陷阱的工作原理。从你的问题来看,这似乎很幸运。

  • _generic操作于$BASH_COMMAND,是一个字符串。_specific使用 的求值参数数组$BASH_COMMAND,尽管如此$BASH_COMMAND仍然可用。原则上,您应该使用数组(或其元素),即"$@"(或"$1""$2",...)。我可以想象$BASH_COMMAND可能用于一些巫术。

  • 调用 时,您可以使用eval "_specific ${BASH_COMMAND#/}"而不是eval "_specific $BASH_COMMAND"来去除前导。请注意,如果您这样做,并且命令是,则的第一个参数将是,而不是空字符串。因此,您可能只想去除内部的前导(例如)。/_specific/ whatever …_specificwhatever/_specificargument1="${1#/}"

  • 扩展代码以覆盖更多前缀很简单:构建任意数量的特定函数并添加更多案例case

  • 该解决方案的核心是DEBUG用于调试的陷阱,因此它会尝试不干扰 stdin、stdout 或退出状态。在以下情况下,我们的_specific无法完全替代,或。解决方案是/foo<input /foo >output/foo | wc -c/foo || whatevercommand_not_found_handle在这些方面会更好,但它只会在不是有效命令时才会启动/foo;所以它可能对/arg1或有效/bin/nonexistent,但对 无效/bin/echo。(比较这个答案:如何使用别名为 bash 创建命令前缀?

相关内容