# bashwrap function: given a function name and code to run before and/or after,
# wrap the existing function with the code that comes before and after. The
# before and after code is taken literally and eval'd, so it can do things like
# access "$@" and indeed change "$@" by using shift or set or similar.
bashwrap () {
local command beforecode aftercode type unset_extglob n
local innerfuncname innerfunccode
local -n varname
command="$1"
beforecode="$2"
aftercode="$3"
# Check the current state of extglob: this code needs it to be set,
# but it should be reset to avoid unexpected changes to the global
# envirnoment.
if ! shopt -q extglob; then
unset_extglob=YesPlease
shopt -s extglob
fi
# Tidy the before and after code: trim whitespace from the start and end,
# and make sure they end with a single semicolon.
for varname in beforecode aftercode; do
varname="${varname##+([$'\n\t '])}"
varname="${varname%%+([$'\n\t '])}"
if [[ "$varname" ]]; then
varname="${varname%%+(;)};"
fi
done
# Now finished with extglob.
if [[ "$unset_extglob" ]]; then shopt -u extglob; fi
type="$(type -t "$command")"
case "$type" in
alias)
printf "bashwrap doesn't (yet) know how to handle aliases\n" >&2
return 69 # EX_UNAVAILABLE
;;
keyword)
printf 'bashwrap cannot wrap Bash keywords\n' >&2
return 64 # EX_USAGE
;;
builtin|file)
eval "$command () { $beforecode command $command \"\$@\"; $aftercode }"
;;
function)
# Keep generating function names until we get to one that doesn't
# exist. This allows a function to be wrapped multiple times; the
# original function will always have the name
# _bashwrapped_0_<name>.
n=0
innerfuncname="_bashwrapped_${n}_$command"
while declare -Fp -- "$innerfuncname" &>/dev/null; do
innerfuncname="_bashwrapped_$((++n))_$command"
done
# Define a new function with the new function name and the old function
# code.
innerfunccode="$(declare -fp -- "$command")"
eval "${innerfunccode/#$command /$innerfuncname }"
# Redefine the existing function to call the new function, in
# between the wrapper code.
eval "$command () { $beforecode $innerfuncname \"\$@\"; $aftercode }"
;;
'')
printf 'Nothing called %q found to wrap\n' "$command" >&2
return 64 # EX_USAGE
;;
*)
printf 'Unexpected object type %s\n' "$type" >&2
return 70 # EX_SOFTWARE
;;
esac
}
$ type echo
echo is a shell builtin
$ bashwrap echo 'command echo "==> "'
$ type echo
echo is a function
echo ()
{
command echo "==> ";
command echo "$@"
}
3条答案
按热度按时间j5fpnvbx1#
近了
字符串
builtin
强制命令的其余部分作为内置函数执行,这简化了内置函数的重新实现。但是,您的问题在于没有引用
>
。t98cgbkg2#
我不太明白你的意思,但也许这会有帮助...
第一个月
.这里我假设
==>
是你总是想要前缀的字符。(note反斜杠
\
,您需要防止>
被解释为重定向。jogvjijk3#
受Python装饰器的启发,我写了一个函数来 Package bash函数、内置命令和对可执行文件的调用。
字符串
原始问题中的简单情况可以如下处理;使用
command
来避免echo
调用我们正在创建的函数。型
您可以使用
type
来查看幕后发生的事情:型
这也允许更复杂的 Package ,包括重复 Package 函数:
型