Создайте псевдоним Bash, который принимает параметр?

Я использовал CShell ( csh ), который позволяет создавать псевдоним, который принимает параметр. Обозначение было чем-то вроде

alias junk="mv \\!* ~/.Trash" 

В Bash это не работает. Учитывая, что у Bash множество полезных функций, я бы предположил, что этот был реализован, но мне интересно, как это сделать.

    Атрибут Bash напрямую не принимает параметры. Вам нужно будет создать функцию и псевдоним.

    alias не принимает параметры, но функция может быть вызвана как псевдоним. Например:

     myfunction() { #do things with parameters like $1 such as mv "$1" "$1.bak" cp "$2" "$1" } myfunction old.conf new.conf #calls `myfunction` 

    Кстати, функции Bash, определенные в вашем .bashrc и другие файлы доступны в виде команд внутри вашей оболочки. Так, например, вы можете вызвать более раннюю функцию, подобную этой

     $ myfunction original.conf my.conf 

    Исправляя ответ выше, вы можете получить 1-строчный синтаксис, как вы можете, для псевдонимов, что более удобно для ad-hoc-определений в файлах оболочки или .bashrc:

     bash$ myfunction() { mv "$1" "$1.bak"; cp "$2" "$1"; } bash$ myfunction original.conf my.conf 

    Не забывайте, что полуколока перед закрывающей правой скобкой. Аналогично, для фактического вопроса:

     csh% alias junk="mv \\!* ~/.Trash" bash$ junk() { mv "[email protected]" ~/.Trash/; } 

    Или:

     bash$ junk() { for item in "[email protected]" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; } 

    Вопрос просто задан неправильно. Вы не делаете псевдоним, который принимает параметры, потому что alias просто добавляет второе имя для того, что уже существует. Функциональность, которую хочет выполнить OP, – это команда function для создания новой функции. Вам не нужно выполнять функцию, поскольку функция уже имеет имя.

    Я думаю, вам нужно что-то вроде этого:

     function trash() { mv "[email protected]" ~/.Trash; } 

    Это оно! Вы можете использовать параметры $ 1, $ 2, $ 3 и т. Д. Или просто наполнить их всеми $ @

    TL; DR: сделайте это вместо этого

    Его гораздо проще и читабельнее использовать функцию, чем псевдоним, чтобы поставить аргументы в середине команды.

     $ wrap_args() { echo "before [email protected] after"; } $ wrap_args 1 2 3 before 1 2 3 after 

    Если вы читаете, вы узнаете, что вам не нужно знать о обработке аргументов оболочки. Знание опасно. Просто получите результат, который вы хотите, прежде чем темная сторона навсегда контролирует вашу судьбу.

    осветление

    bash aliases действительно принимают аргументы, но только в конце :

     $ alias speak=echo $ speak hello world hello world 

    Ввод аргументов в середину команды через alias действительно возможен, но он становится уродливым.

    Не пытайтесь это дома, детишки!

    Если вам нравится обходить ограничения и делать то, что говорят другие, это рецепт. Только не обвиняйте меня, если ваши волосы будут измотаны, и ваше лицо закончится тем, что в сумеречном ученом стиле.

    Обходной путь состоит в том, чтобы передать аргументы, которые alias принимает только в конце обертки, которая будет вставлять их в середину, а затем выполнить вашу команду.

    Решение 1

    Если вы действительно против использования функции как таковой, вы можете использовать:

     $ alias wrap_args='f(){ echo before "[email protected]" after; unset -ff; }; f' $ wrap_args xyz before xyz after 

    Вы можете заменить [email protected] на $1 если вам нужен только первый аргумент.

    Объяснение 1

    Это создает временную функцию f , которой передаются аргументы (обратите внимание, что f вызывается в самом конце). Функция unset -f удаляет определение функции по мере выполнения псевдонима, чтобы впоследствии не зависать.

    Решение 2

    Вы также можете использовать подоболочку:

     $ alias wrap_args='sh -c '\''echo before "[email protected]" after'\'' _' 

    Пояснение 2

    Псевдоним строит команду:

     sh -c 'echo before "[email protected]" after' _ 

    Комментарии:

    • Заполнитель _ требуется, но это может быть что угодно. Он устанавливается в sh $0 и требуется, чтобы первый из заданных пользователем аргументов не потреблялся. Демонстрация:

       sh -c 'echo Consumed: "$0" Printing: "[email protected]"' alcohol drunken babble Consumed: alcohol Printing: drunken babble 
    • Требуются одиночные кавычки внутри одиночных кавычек. Вот пример того, что он не работает с двойными кавычками:

       $ sh -c "echo Consumed: $0 Printing: [email protected]" alcohol drunken babble Consumed: -bash Printing: 

      Здесь значения интерактивной оболочки $0 и [email protected] заменяются на двойные кавычки, прежде чем они передаются в sh . Вот доказательство:

       echo "Consumed: $0 Printing: [email protected]" Consumed: -bash Printing: 

      Одиночные кавычки гарантируют, что эти переменные не интерпретируются интерактивной оболочкой и передаются буквально в sh -c .

      Вы можете использовать двойные кавычки и \[email protected] , но лучше всего процитировать ваши аргументы (так как они могут содержать пробелы), а \"\[email protected]\" выглядит еще более уродливым, но может помочь вам выиграть конкурс обфускации, где измученные волосы является предварительным условием для входа.

    Альтернативное решение – использовать маркер , инструмент, который я создал недавно, что позволяет вам «закладок» шаблонов команд и легко помещать курсор в держатели команд:

    маркер командной строки

    Я обнаружил, что большую часть времени я использую функции оболочки, поэтому мне не нужно писать часто используемые команды снова и снова в командной строке. Проблема использования функций для этого варианта использования заключается в добавлении новых терминов в словарь моей команды и необходимости запоминать, какие параметры функций относятся к реальной команде. objective маркера – устранить эту психическую нагрузку.

    Вот три примера функций, которые у меня есть в моем ~/.bashrc , которые по существу являются псевдонимами, которые принимают параметр:

     #Utility required by all below functions. #https://stackoverflow.com/questions/369758/how-to-trim-whitespace-from-bash-variable#comment21953456_3232433 alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'" 

    ,

     :< 

    ,

     :< 

    ,

     :< /tmp/history #Clear all items in the current sessions history (in memory). This #empties out $HISTFILE. history -c #Overwrite the actual history file with the temp one. mv /tmp/history "$HISTFILE" #Now reload it. history -r "$HISTFILE" #Alternative: exec bash else echo "Cancelled." fi } 

    Рекомендации:

    NB: В случае, если идея не очевидна, плохая идея использовать псевдонимы для чего угодно, кроме псевдонимов, первая из которых является «функцией в псевдониме», а вторая – «трудно читаемой переадресацией / источником». Кроме того, есть недостатки (которые, как я думал, были бы очевидны, но на всякий случай вы смущены: я не имею в виду, что они действительно будут использоваться … где угодно!)

    ………………………………………….. ………………………………………….. ……………………………………..

    Я уже говорил об этом раньше, и в прошлом это всегда было так:

     alias foo='__foo() { unset -f $0; echo "arg1 for foo=$1"; }; __foo()' 

    который является прекрасным и хорошим, если вы не избегаете использования функций вместе. в этом случае вы можете воспользоваться огромной способностью bash перенаправлять текст:

     alias bar='cat <<< '\''echo arg1 for bar=$1'\'' | source /dev/stdin' 

    Они оба примерно одинаковой длины дают или принимают несколько символов.

    Реальный кикер - это разница во времени, верхняя часть - это «метод функции», а нижняя - метод «redirect-источник». Чтобы доказать эту теорию, время говорит само за себя:

     arg1 for foo=FOOVALUE real 0m0.011s user 0m0.004s sys 0m0.008s # <--time spent in foo real 0m0.000s user 0m0.000s sys 0m0.000s # <--time spent in bar arg1 for bar=BARVALUE [email protected] /usr/bin# time foo FOOVALUE; time bar BARVALUE arg1 for foo=FOOVALUE real 0m0.010s user 0m0.004s sys 0m0.004s real 0m0.000s user 0m0.000s sys 0m0.000s arg1 for bar=BARVALUE [email protected] /usr/bin# time foo FOOVALUE; time bar BARVALUE arg1 for foo=FOOVALUE real 0m0.011s user 0m0.000s sys 0m0.012s real 0m0.000s user 0m0.000s sys 0m0.000s arg1 for bar=BARVALUE [email protected] /usr/bin# time foo FOOVALUE; time bar BARVALUE arg1 for foo=FOOVALUE real 0m0.012s user 0m0.004s sys 0m0.004s real 0m0.000s user 0m0.000s sys 0m0.000s arg1 for bar=BARVALUE [email protected] /usr/bin# time foo FOOVALUE; time bar BARVALUE arg1 for foo=FOOVALUE real 0m0.010s user 0m0.008s sys 0m0.004s real 0m0.000s user 0m0.000s sys 0m0.000s arg1 for bar=BARVALUE 

    Это нижняя часть около 200 результатов, выполненных с произвольными интервалами. Кажется, что создание / уничтожение функции занимает больше времени, чем redirect. Надеюсь, это поможет будущим посетителям этого вопроса (не хотелось бы держать это в себе).

    Для принятия параметров вы должны использовать функции!

    Однако $ @ get интерпретируется при создании псевдонима, а не во время выполнения псевдонима, а escape-код не работает. Как решить эту проблему?

    Вам нужно использовать функцию оболочки вместо псевдонима, чтобы избавиться от этой проблемы. Вы можете определить foo следующим образом:

     function foo() { /path/to/command "[email protected]" ;} 

    ИЛИ

     foo() { /path/to/command "[email protected]" ;} 

    Наконец, вызовите ваш foo (), используя следующий синтаксис:

     foo arg1 arg2 argN 

    Убедитесь, что вы добавили файл foo () в файл ~/.bash_profile или ~/.zshrc .

    В вашем случае это будет работать

     function trash() { mv [email protected] ~/.Trash; } 

    Есть законные технические причины, чтобы хотеть обобщенное решение проблемы псевдонимов 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 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([email protected])"; 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=("[email protected]"); # 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 [@]}».

    И т.п.

    Если вы ищете общий способ применения всех параметров к функции, а не только одну или две или некоторые другие жестко запрограммированные суммы, вы можете сделать это следующим образом:

     #!/usr/bin/env bash # you would want to `source` this file, maybe in your .bash_profile? function runjar_fn(){ java -jar myjar.jar "[email protected]"; } alias runjar=runjar_fn; 

    Таким образом, в приведенном выше примере я runjar все параметры с того момента, когда я запускаю runjar в псевдоним.

    Например, если бы я сделал runjar hi there это закончилось бы фактически запущенным java -jar myjar.jar hi there . Если бы я runjar one two three он запустил java -jar myjar.jar one two three .

    Мне нравится это решение на основе [email protected] потому что оно работает с любым количеством параметров.

    Функции действительно являются почти всегда ответом, как это уже было сделано и подтверждено этой цитатой на странице руководства: «Для почти каждой цели псевдонимы заменяются функциями оболочки».

    Для полноты и потому, что это может быть полезно (незначительно более легкий синтаксис), можно отметить, что когда параметры (параметры) следуют за псевдонимом, они все равно могут использоваться (хотя это не будет отвечать требованию OP). Это, вероятно, проще всего продемонстрировать на примере:

     alias ssh_disc='ssh -O stop' 

    позволяет мне ssh_disc myhost , как ssh_disc myhost , который расширяется, как ожидалось: ssh -O stop myhost

    Это может быть полезно для команд, которые принимают сложные аргументы (моя память больше не используется)

    Однако вам не нужны функции при создании псевдонимов в файле .bashrc . Например

     # create an alias that takes port-number by the user alias serve="python -m SimpleHTTPServer $1" 

    После внесения изменений в файл .bashrc убедитесь, что вы вводите следующую команду.

     ~$ source .bashrc 

    Вы должны иметь возможность использовать это так

     ~$ serve 8998 
    Давайте будем гением компьютера.