Есть законные технические причины, чтобы хотеть обобщенного решения проблемы псевдонима bash, не имеющего механизма для принятия произвольных аргументов. Одна из причин заключается в том, что на команду, которую вы хотите выполнить, негативно повлияют изменения в среде, возникшие в результате выполнения функции. Во всех остальных случаях следует использовать функции.
Что недавно заставило меня попытаться решить эту проблему, так это то, что я хотел создать несколько сокращенных команд для печати определений переменных и функций. Поэтому я написал несколько функций для этой цели. Однако существуют определенные переменные, которые (или могут быть) изменены самим вызовом функции. Среди них:
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:
# (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 [@]}".
И т.п.