Istnieją uzasadnione techniczne powody, aby chcieć uogólnionego rozwiązania problemu aliasu bash, który nie ma mechanizmu przejmowania arbitralnych argumentów. Jednym z powodów jest to, że na polecenie, które chcesz wykonać, miałyby negatywny wpływ zmiany środowiska wynikające z wykonania funkcji. We wszystkich innych przypadkach należy korzystać z funkcji.
To, co ostatnio zmusiło mnie do podjęcia próby rozwiązania tego, to to, że chciałem stworzyć kilka skróconych poleceń do drukowania definicji zmiennych i funkcji. Więc napisałem kilka funkcji w tym celu. Istnieją jednak pewne zmienne, które są (lub mogą być) zmieniane przez samo wywołanie funkcji. Wśród nich są:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
Podstawowe polecenie, którego użyłem (w funkcji) do drukowania defns zmiennych. w postaci danych wyjściowych polecenia set:
sv () { set | grep --color=never -- "^$1=.*"; }
Na przykład:
> V=voodoo
sv V
V=voodoo
Problem: Nie spowoduje to wydrukowania wyżej wymienionych definicji zmiennych, ponieważ znajdują się one w bieżącym kontekście , np. Jeśli w interaktywnym pytaniu powłoki (lub nie w żadnym wywołaniu funkcji) FUNCNAME nie jest zdefiniowany. Ale moja funkcja mówi mi nieprawidłowe informacje:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Jedno z opracowanych przeze mnie rozwiązań zostało wspomniane przez innych w innych postach na ten temat. W tym konkretnym poleceniu wypisania zmiennych defns., Które wymaga tylko jednego argumentu, zrobiłem to:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
Co daje poprawne dane wyjściowe (brak) i status wyniku (false):
> asv FUNCNAME
> echo $?
1
Jednak nadal czułem się zmuszony do znalezienia rozwiązania, które zadziałałoby dla dowolnej liczby argumentów.
Ogólne rozwiązanie dotyczące przekazywania arbitralnych argumentów do polecenia aliasowego 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".
Na przykład:
> . 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
Zaletą tego rozwiązania jest to, że wszystkie specjalne sztuczki używane do obsługi parametrów pozycyjnych (argumentów) poleceń działają podczas tworzenia polecenia uwięzionego. Jedyną różnicą jest to, że należy użyć składni tablicy.
Na przykład,
Jeśli chcesz „$ @”, użyj „$ {CMD_ARGV [@]}”.
Jeśli chcesz „$ #”, użyj „$ {# CMD_ARGV [@]}”.
Itp.