Es gibt legitime technische Gründe, eine allgemeine Lösung für das Problem des Bash-Alias zu wollen, der keinen Mechanismus hat, um willkürliche Argumente neu zu positionieren. Ein Grund ist, wenn der Befehl, den Sie ausführen möchten, durch die Änderungen an der Umgebung, die sich aus der Ausführung einer Funktion ergeben, beeinträchtigt wird. In allen anderen Fällen sollten Funktionen verwendet werden.
Was mich kürzlich dazu gezwungen hat, eine Lösung dafür zu finden, ist, dass ich einige abgekürzte Befehle zum Drucken der Definitionen von Variablen und Funktionen erstellen wollte. Deshalb habe ich einige Funktionen für diesen Zweck geschrieben. Es gibt jedoch bestimmte Variablen, die durch einen Funktionsaufruf selbst geändert werden (oder werden können). Unter ihnen sind:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
Der grundlegende Befehl, den ich (in einer Funktion) zum Drucken von Variablendefinitionen verwendet hatte. In der vom Befehl set ausgegebenen Form war:
sv () { set | grep --color=never -- "^$1=.*"; }
Z.B:
> V=voodoo
sv V
V=voodoo
Problem: Dadurch werden die Definitionen der oben genannten Variablen nicht gedruckt, da sie sich im aktuellen Kontext befinden , z. B. wenn in einer interaktiven Shell-Eingabeaufforderung (oder nicht in Funktionsaufrufen) FUNCNAME nicht definiert ist. Aber meine Funktion sagt mir die falschen Informationen:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Eine Lösung, die ich gefunden habe, wurde von anderen in anderen Beiträgen zu diesem Thema erwähnt. Für diesen speziellen Befehl zum Drucken von Variablendefinitionen, für den nur ein Argument erforderlich ist, habe ich Folgendes getan:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
Welches gibt die richtige Ausgabe (keine) und Ergebnisstatus (falsch):
> asv FUNCNAME
> echo $?
1
Ich fühlte mich jedoch immer noch gezwungen, eine Lösung zu finden, die für eine beliebige Anzahl von Argumenten funktioniert.
Eine allgemeine Lösung zum Übergeben beliebiger Argumente an einen Bash-Alias-Befehl:
# (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".
Z.B:
> . 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
Eine schöne Sache an dieser Lösung ist, dass alle speziellen Tricks, die zum Behandeln von Positionsparametern (Argumenten) für Befehle verwendet werden, beim Erstellen des eingeschlossenen Befehls funktionieren. Der einzige Unterschied besteht darin, dass die Array-Syntax verwendet werden muss.
Z.B,
Wenn Sie "$ @" möchten, verwenden Sie "$ {CMD_ARGV [@]}".
Wenn Sie "$ #" möchten, verwenden Sie "$ {# CMD_ARGV [@]}".
Usw.