有没有办法让这个示例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
可能是邪恶的。据我所知,eval
uating$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 …
_specific
whatever
/
_specific
argument1="${1#/}"
扩展代码以覆盖更多前缀很简单:构建任意数量的特定函数并添加更多案例
case
。该解决方案的核心是
DEBUG
用于调试的陷阱,因此它会尝试不干扰 stdin、stdout 或退出状态。在以下情况下,我们的_specific
无法完全替代,或。解决方案是/foo
<input /foo >output
/foo | wc -c
/foo || whatever
command_not_found_handle
在这些方面会更好,但它只会在不是有效命令时才会启动/foo
;所以它可能对/arg1
或有效/bin/nonexistent
,但对 无效/bin/echo
。(比较这个答案:如何使用别名为 bash 创建命令前缀?)