有正当的技术原因需要一个通用的解决方案来解决 bash 别名没有一种机制来重新定位任意参数的问题。一个原因是,如果您希望执行的命令会受到执行函数导致的环境变化的不利影响。在所有其他情况下,都应该使用函数。
最近迫使我尝试解决这个问题的原因是我想创建一些缩写命令来打印变量和函数的定义。所以我为此编写了一些函数。但是,函数调用本身会(或可能)更改某些变量。其中有:
功能名称
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")
其他人在有关此主题的其他帖子中提到了我提出的一个解决方案。对于这个打印变量定义的特定命令,并且只需要一个参数,我这样做了:
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[@]}”。
等等