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


1273

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

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

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



2
Убедитесь, что вы используете кавычки вокруг args"$1"
Кристоф Русси

Этот вопрос не по теме для SO. Он ответил на UNIX.SE , и ответ на то , что вам даже не нужно беспокоиться: «Например, если бы вы были псевдоним lsдля ls -la, затем набрав ls foo barбудет действительно выполнить ls -la foo barв командной строке.»
Дан Даскалеску

7
это не помогло бы с интерполяцией переменной в середину строки
Франц Ситтампалам

1
Вот псевдоним теста lil, который я использовал, чтобы обнаружить эту ошибку ... alias test_args="echo PREFIX --$1-- SUFFIX", которая при вызове с test_args ABCDприводит к следующему выводу консолиPREFIX ---- SUFFIX ABCD
jxramos

Ответы:


2126

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

48
Должен ли я заключить $1в кавычки?
Юрген Пауль

263
Вам даже не нужно объявлять псевдоним. Просто определение функции будет делать.
Дениго

207
Если вы изменяете псевдоним для функции, использование sourceвашего .bashrc добавит функцию, но не сглаживает старый псевдоним. Поскольку псевдонимы имеют более высокий прецедент, чем функции, он будет пытаться использовать псевдоним. Вам нужно либо закрыть и снова открыть свою оболочку, либо позвонить unalias <name>. Возможно, я спасу кого-то 5 минут, которые я потратил впустую.
Марти Нил

56
@MartinNeal: Один из способов сэкономить время, который я усвоил в Sun, заключается в том, чтобы просто выполнить команду exec bash: она запустит новую оболочку, которая даст вам полное представление о ваших конфигах, как если бы вы закрывали и открывали заново, но сохраняя настройки переменных среды этого сеанса тоже , Кроме того, выполнение bashбез exec может быть полезно, когда вы хотите обрабатывать мысли как стек.
Макнейл Шонл

21
@mich - да, всегда помещайте переменные bash в кавычки. например mv "$1" "$1.bak". без кавычек, если бы $ 1 был "привет миром", вы бы выполняли mv hello world hello world.bakвместо mv "hello world" "hello world.bak".
orion elenzil

208

Уточняя ответ выше, вы можете получить 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 "$@" ~/.Trash/; }

Или:

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

3
Я предпочитаю этот ответ, поскольку он показывает итерацию массива аргументов, которые могут прийти.
Philo Vivero

16
Изменение mv "$1" "$1.bak"; cp "$2" "$1" в mv "$1" "$1.bak" && cp "$2" "$1"не потерять свои данные , когда mvсталкивается с трудностями (например, файловая система полностью).
Хенк Лангевельд

3
«Не забывайте точку с запятой перед закрывающей правой скобкой». Много раз это! Спасибо :)
Kaushal Modi

И пробелы после первой скобки и перед последней скобкой также требуются.
Брайан Чапел

1
@HenkLangeveld Хотя ваше замечание совершенно правильно, оно показывает, что вы были здесь некоторое время - я не знаю, когда в последний раз сталкивался с ошибкой «на устройстве не осталось места» ;-). (Я использую это регулярно, хотя, когда я больше не нахожу место на кухонном столе!) В наши дни, кажется, это происходит не очень часто.
Питер - Восстановить Монику

124

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

Я думаю, что вы хотите что-то вроде этого:

function trash() { mv "$@" ~/.Trash; }

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


7
Этот ответ говорит обо всем. Если бы я читал в нижней части этой страницы, я бы сэкономил время.
Джо

-1 Псевдоним и функция не эквивалентны ...echo -e '#!/bin/bash\nshopt -s expand_aliases\nalias asrc='\''echo "${BASH_SOURCE[0]}"'\'' # note the '\''s\nfunction fsrc(){ echo "${BASH_SOURCE[0]}";}'>>file2&&echo -e '#!/bin/bash\n. file2\nalias rl='\''readlink -f'\''\nrl $(asrc)\nrl $(fsrc)'>>file1&&chmod +x file1&&./file1;rm -f file1 file2
Fuzzy Logic

Вы действительно должны цитировать, $@чтобы поддерживать имена файлов с пробелами и т. Д.
Том Хейл,

Предполагалось, что это общее объяснение того, что у вас нет параметров псевдонимов, вместо этого вы используете функцию. Данная функция была просто примером для противодействия исходному примеру. Я не думаю, что человек искал функцию мусора общего назначения. Однако в интересах представления лучшего кода я обновил ответ.
Эван Ланглуа

1
@FuzzyLogic - я потратил несколько минут, чтобы распаковать код в вашем комментарии. Это большое (интересное) усилие, которое нужно выполнить, чтобы упаковать некоторый код в комментарий, который нельзя правильно отформатировать. Я до сих пор не понял, что именно он делает или, что более важно, почему он поддерживает ваше (правильное) утверждение.
Джо

110

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

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

$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after

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

осветление

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

$ alias speak=echo
$ speak hello world
hello world

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

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

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

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

Решение 1

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

$ alias wrap_args='f(){ echo before "$@" after;  unset -f f; }; f'
$ wrap_args x y z
before x y z after

Вы можете заменить $@на, $1если вы хотите только первый аргумент.

Объяснение 1

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

Решение 2

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

$ alias wrap_args='sh -c '\''echo before "$@" after'\'' _'

Объяснение 2

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

sh -c 'echo before "$@" after' _

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

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

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
  • Одиночные кавычки внутри одинарных кавычек обязательны. Вот пример того, как он не работает с двойными кавычками:

    $ sh -c "echo Consumed: $0 Printing: $@" alcohol drunken babble
    Consumed: -bash Printing:

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

    echo "Consumed: $0 Printing: $@"
    Consumed: -bash Printing:

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

    Вы можете использовать двойные кавычки и \$@, но лучше всего указывать свои аргументы (так как они могут содержать пробелы), и \"\$@\"выглядит еще страшнее, но может помочь вам выиграть конкурс на запутывание, где запутанные волосы являются обязательным условием для участия.


2
для решения 1 убедитесь, что вы используете одинарные кавычки, и избегайте \ "вокруг $ @. Очень полезная техника, если она вам нужна. ty.
sgtz

Решение 1 сработало для меня, оберните rdesktop-vrdp аргументом для каждого сервера, который я хочу.
декабря

Принятие аргументов в конце - это как раз то, что мне нужно было заменить «git checkout {branchname}» на простое «gc {branchname}». В .bash_profile мне просто нужно было добавитьalias gc='git checkout'
AbstractVoid

@sgtz почему вы хотите удалить цитаты вокруг $@? Они необходимы, если у вас есть, например, файлы с пробелами в них.
Том Хейл

@ TomHale Это в некоторой степени лингвистика, но решение 1 не очень полезно, если кто-то действительно против использования функции (какой бы ни была причина), поскольку вы сразу после этого признаетесь, что переносите определение функции только на время выполнения псевдоним. во-вторых, «псевдонимы bash принимают аргументы, но только в конце» - это больше семантика: псевдонимы по определению являются заменой слов на строки. им не нужно принимать аргументы, однако команды, которые выполняются посредством подстановки, могут. псевдоним - это замена персонажа, ни больше, ни меньше. нет?
BUFU

39

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

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

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


14

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

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

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


5
Это умно, но кроме того факта, что вопрос определил создание псевдонима, есть ли причина не просто создавать функцию с тем же именем, что и псевдоним изначально?
xaxxon

1
@xaxxon Не совсем, но я знаю, что это самый простой способ использовать псевдоним, а не функцию.
Кен Тран

1
Это не работает. На Ubuntu 18 я получаю ошибку bash: syntax error near unexpected token '{mkdir'.
Шиталь Шах

пропуская трейлинг ;внутри функции, _mkcdскорее всего, ошибка в этом.
Jetchisel

Оставьте место до и после {и}
hesham_EE

10

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

#Utility required by all below functions.
#/programming/369758/how-to-trim-whitespace-from-bash-variable#comment21953456_3232433
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: https://stackoverflow.com/a/3232082/2736496
    - Alias w/param: https://stackoverflow.com/a/7131683/2736496
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's 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.
    #- https://stackoverflow.com/a/4296147/2736496
    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's 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
}

Ссылки:


А? Это функция, а не псевдоним. И одна из ваших ссылок - именно этот вопрос.
tripleee

2
Нет, это работает как функция. Как объясняют некоторые ответы здесь, вы не можете создать псевдоним, который принимает параметр. Что вы можете сделать, это написать функцию, что вы и сделали.
tripleee

1
@tripleee С точки зрения новичка в bash, прежде чем читать ваш комментарий, я подумал, что это псевдоним (альтернативный способ его создания). Насколько я могу судить, он функционирует в точности как один. По сути, это псевдоним, который принимает параметр, даже если я не согласен с терминологией. Я не вижу проблемы. Я уточнил ссылку на другой ответ в этой проблеме. Это помогло мне создать это.
aliteralmind

1
Возможно, это не дает конкретного ответа на вопрос «псевдонима bash, который принимает параметр», потому что теперь я понимаю, что это невозможно, но, безусловно, эффективно на него отвечает. Что мне здесь не хватает?
aliteralmind

2
Здесь есть несколько действительно хороших примеров и хорошо прокомментированный код. Отличная помощь для людей, заходящих на эту страницу.
Чим

9

Bash псевдоним абсолютно принимает параметры. Я просто добавил псевдоним, чтобы создать новое приложение реагирования, которое принимает имя приложения в качестве параметра. Вот мой процесс:

Откройте bash_profile для редактирования в нано

nano /.bash_profile

Добавьте ваши псевдонимы, по одному в строке:

alias gita='git add .'
alias gitc='git commit -m "$@"'
alias gitpom='git push origin master'
alias creact='npx create-react-app "$@"'

примечание: «$ @» принимает параметры, переданные как «creact my-new-app»

Сохраните и выйдите из нано-редактора

Ctrl + O, чтобы написать (нажмите Enter); Ctrl + X для выхода

Скажите терминалу использовать новые псевдонимы в .bash_profile

source /.bash_profile

Это оно! Теперь вы можете использовать ваши новые псевдонимы


6

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


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

1
Второй (псевдоним бара) имеет несколько побочных эффектов. Во-первых, команда не может использовать стандартный ввод. Во-вторых, если после псевдонима не предоставлено никаких аргументов, вместо него передаются все аргументы, которые имеет оболочка. Использование функции позволяет избежать всех этих побочных эффектов. (Также бесполезное использование кошки).
гейра

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

1
Поскольку все такты бара равны нулю, я подозреваю, что оболочка не синхронизирует это правильно. Обратите внимание, что сообщение времени печатается до запуска команды? Поэтому он ничего не делает, а затем выполняет бар, так что вы вообще не измеряете бар. Сделайте что-нибудь более сложное, или сделайте большую петлю в баре, чтобы вы могли сделать более очевидным, что вы ничего не
рассчитываете

1
Теперь я попробовал это (хотя мне пришлось заменить последний __foo () на __foo). time for i in {1..1000}; do foo FOOVALUE; done→ 0m0,028s. Но time for i in {1..1000}; do bar FOOVALUE; done→ 0m2.739s. Бар на два порядка медленнее, чем foo. Простое использование простой функции вместо псевдонима сокращает время выполнения еще на 30%: function boo() { echo "arg1 for boo=$1" ; }time for i in {1..1000}; do boo FOOVALUE; done→ 0m0.019s.
Арне Бабенхаузерхайде

6

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

#!/usr/bin/env bash

# you would want to `source` this file, maybe in your .bash_profile?
function runjar_fn(){
    java -jar myjar.jar "$@";
}

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.

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


4
почему бы просто не назвать функцию runjarвместо того, чтобы сделать ее псевдонимом для функции? Кажется излишне сложным!
Эван Ланглуа

Функции @EvanLanglois автоматически устанавливаются alias(или передаются свойства вещей alias) в файлы bash? если да, то это просто я не знал, что
Мика

Не понимаю, что ты имеешь в виду. Псевдоним - это другое имя, будь то человек или функция. Итак, вы сделали функцию, затем вы сделали второе имя для функции. В псевдониме нет ничего особенного, это просто второе имя и не требуется. То, что вы вводите в командной строке, может быть внутренней или внешней функцией, поэтому «функция» создает новую команду, а не псевдоним.
Эван Ланглуа

4
Это бессмысленно. Это так же, как alias runjar='java -jar myjar.jar'. Псевдонимы принимают аргументы, но только в конце.
Том Хейл,

6

С уважением ко всем, кто говорит, что вы не можете вставить параметр в середину псевдонима, я только что проверил его и обнаружил, что он работает.

alias mycommand = "python3" $ 1 "script.py --folderoutput RESULTS /"

когда я тогда запустил mycommand foobar, он работал точно так же, как если бы я набрал команду от руки.


Абсолютно, псевдоним может получить параметры, я использую его, например: alias commit = "git commit -m $ 1"
agapitocandemor

Не работает на меня: alias myalias="echo 1 "$1" 3"; myalias 2дает мне:1 3 2
dirdi

4

Есть законные технические причины, чтобы хотеть обобщенного решения проблемы псевдонима 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 [@]}".

И т.п.


3

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

alias cp="~/SCR/spiner cp"

И это сценарий вращения

#!/bin/bash

#Set timer
T=$(date +%s)

#Add some color
. ~/SCR/color

#Animation sprites
sprite=( "(* )  ( *)" " (* )( *) " " ( *)(* ) " "( *)  (* )" "(* )  ( *)" )

#Print empty line and hide cursor
printf "\n${COF}"

#Exit function
function bye { printf "${CON}"; [ -e /proc/$pid ] && kill -9 $pid; exit; }; trap bye INT

#Run our command and get its pid
"$@" & pid=$!

#Waiting animation
i=0; while [ -e /proc/$pid ]; do sleep 0.1

    printf "\r${GRN}Please wait... ${YLW}${sprite[$i]}${DEF}"
    ((i++)); [[ $i = ${#sprite[@]} ]] && i=0

done

#Print time and exit
T=$(($(date +%s)-$T))
printf "\n\nTime taken: $(date -u -d @${T} +'%T')\n"

bye

Это выглядит так

введите описание изображения здесь

Цикличная анимация)

введите описание изображения здесь


2

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

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

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

function foo() { /path/to/command "$@" ;}

ИЛИ

foo() { /path/to/command "$@" ;}

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

foo arg1 arg2 argN

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

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

function trash() { mv $@ ~/.Trash; }

Я не понимаю вашу идею. Я думаю, что это не важно, когда аргументы интерпретируются. Алиас принимает столько параметров, сколько вы хотите в конце.
Тимо

Но лучше сделать это с помощью функций. Псевдонимы не предназначены для этого.
Ахмад

1

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

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

alias ssh_disc='ssh -O stop'

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

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


1

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

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


1
Как вы думаете, почему не работает версия функции?
tripleee

@tripleee. Я отредактировал пост, чтобы сделать его более читабельным. Под заголовком «1. Псевдоним работает, функция ...» я показал, почему не работает версия функции. И, возможно, чтобы ответить на вопрос напрямую, функция вводит новую область, в которой псевдоним отсутствует.
biocyberman

Вы говорите, что это не работает, но я вам не верю. sourceв функции работает просто отлично.
tripleee

1
f () { source /tmp/nst; }делает именно то, что я ожидаю. Может быть, вы PATHне правы, поэтому он работает неправильно activateили что-то; но запуск sourceиз функции работает нормально.
tripleee

1
Кстати, об использовании functionключевого слова в вашем определении см. Wiki.bash-hackers.org/scripting/obsolete - function funcname {древний синтаксис ksh bash поддерживает обратную совместимость с оболочками pre-POSIX, тогда funcname() {как официальный синтаксис POSIX-стандартизирован. function funcname() {это неверное сочетание двух, которое несовместимо с древним ksh или несовместимо с POSIX sh, и поэтому его лучше избегать.
Чарльз Даффи

1

Вот пример:

alias gcommit='function _f() { git add -A; git commit -m "$1"; } ; _f'

Очень важно:

  1. Есть место после {и до }.
  2. Существует ;после каждой команды в последовательности. Если вы забудете об этом после последней команды, >вместо этого вы увидите приглашение!
  3. Аргумент заключен в кавычки как "$1"

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

1

Как уже указывалось другими, использование функции должно рассматриваться как лучшая практика.

Тем не менее, вот еще один подход, используя xargs:

alias junk="xargs -I "{}" -- mv "{}" "~/.Trash" <<< "

Обратите внимание, что это имеет побочные эффекты в отношении перенаправления потоков.


0

Вам не нужно ничего делать, псевдоним делает это автоматически.

Например, если я хочу, чтобы параметр git pull origin master был параметризован, я могу просто создать псевдоним следующим образом:

alias gpull = 'git pull origin '

и при фактическом вызове вы можете передать 'master' (имя ветви) в качестве параметра, например так:

gpull master
//or any other branch
gpull mybranch

Это не отвечает на вопрос, так как аргумент не может быть размещен свободно, но только в конце.
Дирди
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.