Существуют законные технические причины, чтобы хотеть обобщенного решения проблемы псевдонима 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)) <<<'
, который дает правильный вывод (нет) и статус результата (false):
> 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 [@]}".
И т. Д.