任意の引数の位置を変更するメカニズムを持たないbashエイリアスの問題に対する一般化されたソリューションが必要となる正当な技術的理由があります。1つの理由は、実行したいコマンドが、関数の実行に起因する環境の変更によって悪影響を受ける場合です。それ以外の場合はすべて、関数を使用する必要があります。
最近これを解決するように強いられたのは、変数と関数の定義を出力するためのいくつかの省略されたコマンドを作成したかったということです。そこで、そのための関数をいくつか作成しました。ただし、関数呼び出し自体によって変更される(または変更される可能性がある)特定の変数があります。それらの中には:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
変数の定義を出力するために(関数で)使用していた基本的なコマンド。setコマンドの出力形式は次のとおりです。
sv () { set | grep --color=never -- "^$1=.*"; }
例えば:
> V=voodoo
sv V
V=voodoo
問題:上記の変数の定義は現在のコンテキストにあるため、これは出力されません。たとえば、対話型シェルプロンプト(または関数呼び出しではない)の場合、FUNCNAMEは定義されません。しかし、私の関数は間違った情報を教えてくれます:
> sv FUNCNAME
FUNCNAME=([0]="sv")
私が思いついた解決策の1つは、このトピックの他の投稿で他の人から言及されています。この特定のコマンドが変数の定義を出力するために、1つの引数しか必要としないため、これを行いました。
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
正しい出力(なし)と結果のステータス(false)を示します。
> 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 [@]}」を使用します。
等。