出于合理的技术原因,需要一种通用的解决方案来解决bash别名问题,而该机制不具有重新定位任意参数的机制。原因之一是,您希望执行的命令是否会由于执行功能而导致的环境变化受到不利影响。在所有其他情况下,应使用功能。
最近迫使我尝试解决此问题的原因是,我想创建一些缩写命令来打印变量和函数的定义。因此,我为此目的编写了一些函数。但是,某些变量会由函数调用本身更改(或可能会更改)。其中包括:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
我一直使用(在函数中)打印变量defns的基本命令。set命令输出的形式为:
sv () { set | grep --color=never -- "^$1=.*"; }
例如:
> V=voodoo
sv V
V=voodoo
问题:这将不会在当前上下文中显示上述变量的定义,例如,如果在交互式shell提示符下(或不在任何函数调用中),则未定义FUNCNAME。但是我的函数告诉我错误的信息:
> sv FUNCNAME
FUNCNAME=([0]="sv")
我想出的一种解决方案已在其他与此主题相关的文章中提及。对于此仅显示变量defns。且仅需要一个参数的命令,我这样做了:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
给出正确的输出(无)和结果状态(假):
> asv FUNCNAME
> echo $?
1
但是,我仍然感到必须寻找一种适用于任意数量参数的解决方案。
将任意参数传递给Bash别名命令的一般解决方案:
# (I put this code in a file "alias-arg.sh"):
# cmd [arg1 ...] – an experimental command that optionally takes args,
# which are printed as "cmd(arg1 ...)"
#
# Also sets global variable "CMD_DONE" to "true".
#
cmd () { echo "cmd($@)"; declare -g CMD_DONE=true; }
# Now set up an alias "ac2" that passes to cmd two arguments placed
# after the alias, but passes them to cmd with their order reversed:
#
# ac2 cmd_arg2 cmd_arg1 – calls "cmd" as: "cmd cmd_arg1 cmd_arg2"
#
alias ac2='
# Set up cmd to be execed after f() finishes:
#
trap '\''cmd "${CMD_ARGV[1]}" "${CMD_ARGV[0]}"'\'' SIGUSR1;
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# (^This is the actually execed command^)
#
# f [arg0 arg1 ...] – acquires args and sets up trap to run cmd:
f () {
declare -ag CMD_ARGV=("$@"); # array to give args to cmd
kill -SIGUSR1 $$; # this causes cmd to be run
trap SIGUSR1; # unset the trap for SIGUSR1
unset CMD_ARGV; # clean up env...
unset f; # incl. this function!
};
f' # Finally, exec f, which will receive the args following "ac2".
例如:
> . alias-arg.sh
> ac2 one two
cmd(two one)
>
> # Check to see that command run via trap affects this environment:
> asv CMD_DONE
CMD_DONE=true
关于此解决方案的一件好事是,在编写捕获的命令时,所有用于处理命令的位置参数(自变量)的特殊技巧都将起作用。唯一的区别是必须使用数组语法。
例如,
如果要“ $ @”,请使用“ $ {CMD_ARGV [@]}”。
如果要“ $#”,请使用“ $ {#CMD_ARGV [@]}”。
等等。