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

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

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

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

Ответ 1

Псевдоним 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

Ответ 2

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

bash$ myfunction() { mv "$1" "$1.bak" && cp -i "$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; }

Ответ 3

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

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

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

Что это! Вы можете использовать параметры $1, $2, $3 и т.д. Или просто использовать их все с помощью [email protected]

Ответ 4

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 -f f; }; f'
$ wrap_args x y z
before x y z 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]\" выглядит еще более уродливым, но может помочь вам выиграть конкурс обфускации, где измотанные волосы предпосылка для входа.

Ответ 5

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

commandline marker

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

Ответ 6

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

#Utility required by all below functions.
#/questions/10090/how-to-trim-whitespace-from-a-bash-variable/67927#comment192496_67927
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"

.

:<<COMMENT
    Alias function for recursive deletion, with are-you-sure prompt.

    Example:
        srf /home/myusername/django_files/rest_tutorial/rest_venv/

    Parameter is required, and must be at least one non-whitespace character.

    Short description: Stored in SRF_DESC

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*rm -r*:srf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - y/n prompt: /questions/10092/in-bash-how-to-add-are-you-sure-yn-to-any-command-or-alias/67968#67968
    - Alias w/param: /questions/10073/make-a-bash-alias-that-takes-a-parameter/67804#67804
COMMENT
#SRF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
SRF_DESC="srf [path]: Recursive deletion, with y/n prompt\n"
srf()  {
    #Exit if no parameter is provided (if it the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    #Actual line-breaks required in order to expand the variable.
    #- /questions/10091/how-do-i-add-a-line-break-for-read-command/67960#67960
    read -r -p "About to
    sudo rm -rf \"$param\"
Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        sudo rm -rf "$param"
    else
        echo "Cancelled."
    fi
}

.

:<<COMMENT
    Delete item from history based on its line number. No prompt.

    Short description: Stored in HX_DESC

    Examples
        hx 112
        hx 3

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HX_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HX_DESC="hx [linenum]: Delete history item at line number\n"
hx()  {
    history -d "$1"
}

.

:<<COMMENT
    Deletes all lines from the history that match a search string, with a
    prompt. The history file is then reloaded into memory.

    Short description: Stored in HXF_DESC

    Examples
        hxf "rm -rf"
        hxf ^source

    Parameter is required, and must be at least one non-whitespace character.

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*hxf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HXF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HXF_DESC="hxf [searchterm]: Delete all history items matching search term, with y/n prompt\n"
hxf()  {
    #Exit if no parameter is provided (if it the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    read -r -p "About to delete all items from history that match \"$param\". Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        #Delete all matched items from the file, and duplicate it to a temp
        #location.
        grep -v "$param" "$HISTFILE" > /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
}

Ссылки:

Ответ 7

Все, что вам нужно сделать, это сделать функцию внутри псевдонима:

$ alias mkcd='function _mkcd(){mkdir "$1"; cd "$1"}; _mkcd'

Вы должны ставить двойные кавычки вокруг "1 доллара", потому что одинарные кавычки не будут работать.

Ответ 8

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'

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

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

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 результатов, выполненных с произвольными интервалами. Кажется, что создание/уничтожение функции занимает больше времени, чем перенаправление. Надеюсь, это поможет будущим посетителям в этом вопросе (не хотел держать его в покое).

Ответ 9

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

#!/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 hi there, это закончилось бы фактически запуском java -jar myjar.jar hi there. Если бы я сделал runjar one two three, он выполнил бы java -jar myjar.jar one two three.

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

Ответ 10

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

Что недавно заставило меня попытаться решить это, так это то, что я хотел создать некоторые сокращенные команды для печати определений переменных и функций. Поэтому я написал некоторые функции для этой цели. Однако есть определенные переменные, которые (или могут быть) изменены самим вызовом функции. Среди них:

имя_функции 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([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 [@]}".

Etc.

Ответ 11

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

Однако [email protected] интерпретируется при создании псевдонима, а не во время выполнения псевдонима и сбегания $doesnt. Как решить эту проблему?

Вам нужно использовать функцию оболочки вместо псевдонима, чтобы избавиться от этой проблемы. Вы можете определить 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; }

Ответ 12

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

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

alias ssh_disc='ssh -O stop'

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

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

Ответ 13

И функции, и псевдонимы могут использовать параметры, как показано здесь другими. Кроме того, я хотел бы отметить несколько других аспектов:

1. функция работает в своей области видимости, псевдоним разделяет область видимости

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

function tfunc(){
    GlobalFromFunc="Global From Func" # Function set global variable by default
    local FromFunc="onetwothree from func" # Set a local variable

}

alias talias='local LocalFromAlias="Local from Alias";  GlobalFromAlias="Global From Alias" # Cant hide a variable with local here '
# Test variables set by tfunc
tfunc # call tfunc
echo $GlobalFromFunc # This is visible
echo $LocalFromFunc # This is not visible
# Test variables set by talias
# call talias
talias
echo $GlobalFromAlias # This is invisible
echo $LocalFromAlias # This variable is unset and unusable 

Выход:

bash-3.2$     # Test variables set by tfunc
bash-3.2$     tfunc # call tfunc
bash-3.2$     echo $GlobalFromFunc # This is visible
Global From Func
bash-3.2$     echo $LocalFromFunc # This is not visible

bash-3.2$     # Test variables set by talias
bash-3.2$     # call talias
bash-3.2$     talias
bash: local: can only be used in a function
bash-3.2$     echo $GlobalFromAlias # This is invisible
Global From Alias
bash-3.2$ echo $LocalFromAlias # This variable is unset and unusable

2. Скрипт-обёртка - лучший выбор

Несколько раз мне случалось, что псевдоним или функция не могут быть найдены при входе через ssh или при переключении имен пользователей или многопользовательской среды. Есть подсказки и приемы с файлами исходных точек, или этот интересный с псевдонимом: alias sd='sudo ' позволяет этому последующему псевдониму alias install='sd apt-get install' работать как положено (обратите внимание на дополнительное место в sd='sudo '). Однако в таких случаях скрипт-обертка работает лучше, чем функция или псевдоним. Основное преимущество скрипта-обертки в том, что он видимый/исполняемый для заданного пути (то есть /usr/loca/bin/), где в качестве функции/псевдонима необходимо найти источник, прежде чем его можно будет использовать. Например, вы помещаете функцию в ~/.bash_profile или ~/.bashrc для bash, но позже переключаетесь на другую оболочку (то есть zsh), тогда функция больше не отображается. Таким образом, когда вы сомневаетесь, скрипт-обертка всегда является наиболее надежным и переносимым решением.

Ответ 14

Лично я использую Bash, и на моем VPS я в ~/.aliases этот, и он отлично работает:

alias ban = "sudo ufw deny from $ @"

Ответ 15

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

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

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

~$ source .bashrc

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

~$ serve 8998