Existem razões técnicas legítimas para querer uma solução generalizada para o problema de o alias do bash não ter um mecanismo para reposicionar argumentos arbitrários. Uma razão é se o comando que você deseja executar seria afetado negativamente pelas mudanças no ambiente resultantes da execução de uma função. Em todos os outros casos, as funções devem ser usadas.
O que recentemente me levou a tentar uma solução para isso é que eu queria criar alguns comandos abreviados para imprimir as definições de variáveis e funções. Então, eu escrevi algumas funções para esse fim. No entanto, existem certas variáveis que são (ou podem ser) alteradas por uma chamada de função. Entre eles estão:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
O comando básico que eu estava usando (em uma função) para imprimir defns de variáveis. na saída do formulário pelo comando set foi:
sv () { set | grep --color=never -- "^$1=.*"; }
Por exemplo:
> V=voodoo
sv V
V=voodoo
Problema: Isso não imprimirá as definições das variáveis mencionadas acima, como estão no contexto atual , por exemplo, se em um prompt de shell interativo (ou não em nenhuma chamada de função), FUNCNAME não estiver definido. Mas minha função me diz a informação errada:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Uma solução que eu encontrei foi mencionada por outras pessoas em outros posts sobre esse tópico. Para que este comando específico imprima a variável defns., E que requer apenas um argumento, eu fiz o seguinte:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
O que fornece a saída correta (nenhuma) e o status do resultado (falso):
> asv FUNCNAME
> echo $?
1
No entanto, ainda me sentia obrigado a encontrar uma solução que funcionasse para números arbitrários de argumentos.
Uma solução geral para passar argumentos arbitrários para um comando com alias do 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".
Por exemplo:
> . 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
Uma coisa boa dessa solução é que todos os truques especiais usados para manipular parâmetros posicionais (argumentos) para comandos funcionarão ao compor o comando interceptado. A única diferença é que a sintaxe da matriz deve ser usada.
Por exemplo,
Se você deseja "$ @", use "$ {CMD_ARGV [@]}".
Se você quiser "$ #", use "$ {# CMD_ARGV [@]}".
Etc.