Є обґрунтовані технічні причини, щоб хотіти узагальненого вирішення проблеми баш-псевдоніму, який не має механізму прийняття довільних аргументів. Однією з причин є те, якщо на команду, яку ви хочете виконати, негативно впливатимуть зміни в середовищі, які є результатом виконання функції. У всіх інших випадках слід використовувати функції.
Що нещодавно змусило мене спробувати вирішити це те, що я хотів створити кілька скорочених команд для друку визначень змінних та функцій. Тому я написав для цього деякі функції. Однак є певні змінні, які (або можуть бути) змінені самим викликом функції. Серед них:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
Основна команда, яку я використовував (у функції) для друку змінних defns. у формі виведення командою set було:
sv () { set | grep --color=never -- "^$1=.*"; }
Наприклад:
> V=voodoo
sv V
V=voodoo
Проблема: Це не буде друкувати визначення змінних, згаданих вище, як вони є в поточному контексті , наприклад, якщо в інтерактивному запиті оболонки (або ні в будь-яких викликах функцій) FUNCNAME не визначено. Але моя функція повідомляє мені неправильну інформацію:
> sv FUNCNAME
FUNCNAME=([0]="sv")
Одне рішення, яке я придумав, було згадуно іншими в інших публікаціях на цю тему. Для цієї конкретної команди для друку змінних defns., Яка вимагає лише одного аргументу, я зробив це:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
Що дає правильний вихід (немає) та статус результату (помилковий):
> asv FUNCNAME
> echo $?
1
Однак я все ж відчував вимушеність знайти рішення, яке працює для довільної кількості аргументів.
Загальне рішення для передачі довільних аргументів команді Bash Aliased:
# (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".
Наприклад:
> . 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
Приємно в цьому рішенні, що всі спеціальні хитрощі, використовувані для обробки позиційних параметрів (аргументів) до команд, працюватимуть під час складання захопленої команди. Єдина відмінність полягає в тому, що треба використовувати синтаксис масиву.
Наприклад,
Якщо ви хочете "$ @", використовуйте "$ {CMD_ARGV [@]}".
Якщо ви хочете "$ #", використовуйте "$ {# CMD_ARGV [@]}".
І т.д.