Vi sono motivi tecnici legittimi per volere una soluzione generalizzata al problema dell'alias bash che non dispone di un meccanismo per accettare un riposizionamento di argomenti arbitrari. Uno dei motivi è se il comando che si desidera eseguire sarebbe influenzato negativamente dalle modifiche all'ambiente risultanti dall'esecuzione di una funzione. In tutti gli altri casi, è necessario utilizzare le funzioni.
Ciò che recentemente mi ha spinto a tentare una soluzione a questo è che volevo creare alcuni comandi abbreviati per stampare le definizioni di variabili e funzioni. Quindi ho scritto alcune funzioni a tale scopo. Tuttavia, ci sono alcune variabili che sono (o possono essere) modificate da una chiamata di funzione stessa. Tra questi ci sono:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
Il comando di base che stavo usando (in una funzione) per stampare i parametri variabili. nel modulo l'output del comando set era:
sv () { set | grep --color=never -- "^$1=.*"; }
Per esempio:
> V=voodoo
sv V
V=voodoo
Problema: questo non stampa le definizioni delle variabili sopra menzionate così come sono nel contesto corrente , ad esempio, se in un prompt interattivo della shell (o meno in qualsiasi chiamata di funzione), FUNCNAME non è definito. Ma la mia funzione mi dice informazioni sbagliate:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Una soluzione che ho trovato è stata citata da altri in altri post su questo argomento. Per questo comando specifico per stampare variabili defn. E che richiede solo un argomento, ho fatto questo:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
Che fornisce l'output corretto (nessuno) e lo stato del risultato (falso):
> asv FUNCNAME
> echo $?
1
Tuttavia, mi sentivo comunque obbligato a trovare una soluzione che funzionasse per un numero arbitrario di argomenti.
Una soluzione generale per passare argomenti arbitrari 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".
Per esempio:
> . 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
Una cosa bella di questa soluzione è che tutti i trucchi speciali usati per gestire i parametri posizionali (argomenti) ai comandi funzioneranno durante la composizione del comando intercettato. L'unica differenza è che deve essere utilizzata la sintassi dell'array.
Per esempio,
Se vuoi "$ @", usa "$ {CMD_ARGV [@]}".
Se vuoi "$ #", usa "$ {# CMD_ARGV [@]}".
Eccetera.