Existen razones técnicas legítimas para querer una solución generalizada al problema de bash alias que no tiene un mecanismo para tomar una posición de argumentos arbitrarios. Una razón es si el comando que desea ejecutar se vería afectado negativamente por los cambios en el entorno que resultan de ejecutar una función. En todos los demás casos, se deben utilizar funciones.
Lo que recientemente me obligó a intentar una solución a esto es que quería crear algunos comandos abreviados para imprimir las definiciones de variables y funciones. Entonces escribí algunas funciones para ese propósito. Sin embargo, hay ciertas variables que son (o pueden ser) cambiadas por una función llamada en sí. Entre ellos están:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
El comando básico que había estado usando (en una función) para imprimir definiciones variables. en el formulario de salida por el comando set fue:
sv () { set | grep --color=never -- "^$1=.*"; }
P.ej:
> V=voodoo
sv V
V=voodoo
Problema: Esto no imprimirá las definiciones de las variables mencionadas anteriormente, ya que están en el contexto actual , por ejemplo, si en un intérprete de comandos interactivo (o no en ninguna llamada de función), FUNCNAME no está definido. Pero mi función me dice la información incorrecta:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Una solución que se me ocurrió ha sido mencionada por otros en otras publicaciones sobre este tema. Para este comando específico para imprimir defns variables, y que requiere solo un argumento, hice esto:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
Lo que da el resultado correcto (ninguno) y el estado del resultado (falso):
> asv FUNCNAME
> echo $?
1
Sin embargo, todavía me sentí obligado a encontrar una solución que funcione para números arbitrarios de argumentos.
Una solución general para pasar argumentos arbitrarios a un comando con alias 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".
P.ej:
> . 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
Lo bueno de esta solución es que todos los trucos especiales utilizados para manejar los parámetros posicionales (argumentos) de los comandos funcionarán al componer el comando atrapado. La única diferencia es que se debe usar la sintaxis de matriz.
P.ej,
Si desea "$ @", use "$ {CMD_ARGV [@]}".
Si desea "$ #", use "$ {# CMD_ARGV [@]}".
Etc.