Зробити псевдонім Bash, який приймає параметр?


1270

Раніше я використовував CShell (), що дозволяє зробити псевдонім, який приймає параметр. Позначення було щось подібне

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

У Баша це, здається, не працює. Зважаючи на те, що Bash має безліч корисних функцій, я б припустив, що ця реалізована, але мені цікаво, як.



2
Переконайтесь, що ви використовуєте цитати навколо арг"$1"
Крістоф Руссі

Це питання є поза темою для SO. Він відповів на UNIX.SE , і відповідь на те , що вам навіть не потрібно турбуватися: «Наприклад, якщо б ви були псевдонім lsдля ls -la, потім набравши ls foo barбуде дійсно виконати ls -la foo barв командному рядку.»
Дан Даскалеску

7
це не допомогло б з інтерполяцією змінної в середину рядка
Франц Ситтампалам

1
Ось псевдонім lil test, який я використовував для виявлення цієї помилки ... alias test_args="echo PREFIX --$1-- SUFFIX", який при test_args ABCDPREFIX ---- SUFFIX ABCD
виклику

Відповіді:


2122

Псевдонім 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
Вам навіть не потрібно декларувати псевдонім. Просто визначення функції буде робити.
диніго

206
Якщо ви змінюєте псевдонім до функції, sourceваш .bashrc додасть функцію, але це не скасує старий псевдонім. Оскільки псевдоніми є прецедентом вище, ніж функції, він буде намагатися використовувати псевдонім. Вам потрібно або закрити, і знову відкрити оболонку, або ж зателефонувати unalias <name>. Можливо, я врятую когось 5 хвилин, які я просто витратив.
Марті Ніл

55
@MartinNeal: Один фокус економії часу, який я навчився в Sun, - це просто зробити exec bash: він запустить нову оболонку, даючи вам чітке зчитування ваших конфігурацій, так само, як якщо б ви закрили і знову відкрили, але зберігаючи змінні налаштування середовища цього сеансу теж . Крім того, виконання bashбез exec може бути корисним, коли ви хочете обробити думки, як стек.
Macneil Shonle

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

208

Уточнюючи відповідь вище, ви можете отримати однорядковий синтаксис, як можна для псевдонімів, що зручніше для спеціальних визначень у оболонці або .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
Я віддаю перевагу цій відповіді, так як вона показує повторення через масив аргументів, які можуть надійти. $ 1 і $ 2 - це лише окремі випадки, що також проілюстровано у цій відповіді.
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просто додає друге ім’я для чогось, що вже існує. Функціонал, який хоче ОП, - це functionкоманда створити нову функцію. Вам не потрібно псевдонім функції, оскільки функція вже має ім'я.

Я думаю, ти хочеш щось подібне:

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

Це воно! Ви можете використовувати параметри $ 1, $ 2, $ 3 і т.д., або просто заповнити їх усі $ @


7
Ця відповідь говорить усе. Якби я читав знизу цієї сторінки, я би заощадив деякий час.
joe

-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
Нечітка логіка

Ви дійсно повинні цитувати $@підтримку імен файлів з пробілами тощо
Том Хейл,

Це повинно було бути загальним поясненням того, що у вас немає параметрів псевдоніму, ви замість цього використовуєте функцію. Дана функція була лише прикладом протидії вихідному прикладу. Я не думаю, що людина шукала функції сміття загального призначення. Однак, з метою подання кращого коду, я оновив відповідь.
Еван Ланглуа

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

Введення аргументів в середину команди через 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' _

Коментарі:

  • _Потрібний заповнювач , але це може бути будь-що. Він встановлюється на sh's $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, переконайтеся , що ви використовуєте одинарні лапки, і уникнути \ "в навколо $ @ Дуже корисний метод , якщо вам це потрібно ти ...
sgtz

Рішення 1 працювало для мене, щоб обернути rdesktop-vrdp з аргументом для кожного сервера, який я хочу.
Гесхдар

Прийняття аргументів в кінці - саме те, що мені потрібно було замінити "git checkout {branchname}" простим "gc {branchname}". У .bash_profile мені просто довелося додатиalias gc='git checkout'
AbstractVoid

@sgtz, чому ви хочете видалити цитати навколо $@? Вони необхідні, якщо у вас є, наприклад, файли з пробілами.
Том Хейл

@TomHale Це дещо мовознавство, але рішення 1 не дуже корисне, якщо хтось насправді проти використання функції (з будь-якої причини це може бути), оскільки ви безпосередньо після того, як визнаєте себе, ви лише переносите визначення функції на час виконання псевдонім. по-друге, "bash псевдоніми приймають аргументи, але лише в кінці" є більш семантикою: псевдоніми - це визначення заміна слів за рядками. їм не потрібно приймати аргументи, проте команди, які виконуються за допомогою заміни, проте можуть. псевдонім - це заміна символів, нічого більше, нічого менше. ні?
БУФУ

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'.
Shital Shah

відсутній трейлінг ;всередині функції, _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
}

Список літератури:


Так? Це функція, а не псевдонім. І однією з ваших посилань є саме це питання.
трійка

2
Ні, він працює точно як функція. Як і декілька відповідей, пояснених тут, ви не можете зробити псевдонім, який приймає параметр. Те, що ви можете зробити, це написати функцію, яку ви зробили.
трійка

1
@tripleee З моєї точки зору новачка, перед тим, як прочитати ваш коментар, я подумав, що це псевдонім (альтернативний спосіб створити його). Наскільки я можу сказати, вона функціонує точно як одна. Це, по суті , псевдонім, який приймає параметр, навіть якщо я вимкнувся з термінології. Я не бачу проблеми. Я уточнив посилання на іншу відповідь у цій проблемі. Це допомогло мені створити це.
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 "$@"'

зауважте: "$ @" приймає передані параметри типу "create my-new-app"

Збережіть та закрийте наноредактор

ctrl + o to to write (натисніть Enter); ctrl + x для виходу

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

source /.bash_profile

Це воно! Тепер ви можете використовувати свої нові псевдоніми


6

Примітка: Якщо ідея не очевидна, погана ідея використовувати псевдоніми для будь-якого, крім псевдонімів, перший - "функція в псевдонімі", а другий - "важко читати переспрямування / джерело". Крім того, є недоліки (які, я думав , будуть очевидними, але на всякий випадок, коли ви плутаєтесь: я не маю на увазі, що вони насправді використовуються ... де завгодно!)

.................................................. .................................................. ............................................

Я відповідав на це раніше, і це було завжди в минулому:

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
Маючи псевдонім, який визначає функцію, тоді запустити цю функцію просто нерозумно. Просто напишіть функцію. Практично з будь-якою метою псевдоніми витісняються функціями оболонки.
geirha

якщо ви не читали все, що ви можете спробувати, я ілюстрував, чому використання методу функції в першу чергу було не так добре, і, крім того, це зовсім не дурно. Перестаньте публікувати та забороняти публікацію лише тому, що вам це особисто не сподобалось ... або принаймні дати вагомі пояснення. Ім'я покликання - це перша ознака близькості ...
osirisgothra

1
Другий (бар псевдонім) має кілька побічних ефектів. По-перше, команда не може використовувати stdin. По-друге, якщо ніяких аргументів після псевдоніму не наводяться, будь-які аргументи, які трапляються в оболонці, натомість передаються. Використання функції дозволяє уникнути всіх цих побічних ефектів. (Також марне використання кота).
geirha

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

1
Так як тайминги бару все 0, я б підозрювати , що оболонка не синхронізації це правильно. Зауважте, що повідомлення про час друкується перед запуском команди? Ерго, це ніколи не буває, а потім виконує бар, тому ви взагалі не вимірюєте бар. Зробіть щось складніше чи великий цикл у барі, щоб ви могли зробити більш очевидним, що ви нічого не
приділяєте

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-ed (або мають властивості переданих речей alias) у файлах bash? якщо так, то це я просто не знаю
Міхей

Не розумію, що ти маєш на увазі. Псевдонім - це інше ім’я, будь то людина чи функція. Отже, ви зробили функцію, потім ви зробили друге ім’я для функції. У псевдонімі немає нічого особливого, його лише друге ім’я і не потрібно. Те, що ви вводите в командному рядку, можуть бути внутрішніми або зовнішніми функціями, тому "функція" робить нову команду, а не псевдонім.
Еван Ланглуа

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

6

З повагою до всіх тих, хто говорить, що ви не можете вставити параметр посеред псевдоніма, я лише перевірив його і виявив, що він працює.

alias mycommand = "python3" $ 1 "script.py --folderoutput РЕЗУЛЬТАТИ"

коли я запустив команду foobar, він працював точно так, ніби я набрав команду з долоні.


Абсолютно, псевдонім може отримати параметри, я віком використовую цей, наприклад: alias commit = "git commit -m $ 1"
agapitocandemor

Не працює для мене: alias myalias="echo 1 "$1" 3"; myalias 2дає мені:1 3 2
dirdi

4

Є обґрунтовані технічні причини, щоб хотіти узагальненого вирішення проблеми баш-псевдоніму, який не має механізму прийняття довільних аргументів. Однією з причин є те, якщо на команду, яку ви хочете виконати, негативно впливатимуть зміни в середовищі, які є результатом виконання функції. У всіх інших випадках слід використовувати функції.

Що нещодавно змусило мене спробувати вирішити це те, що я хотів створити кілька скорочених команд для друку визначень змінних та функцій. Тому я написав для цього деякі функції. Однак є певні змінні, які (або можуть бути) змінені самим викликом функції. Серед них:

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 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($@)"; 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команди coz, 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

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

Для повноти і тому, що це може бути корисним (незначно ситнішим синтаксисом), можна зазначити, що коли параметр (и) слідують за псевдонімом, вони все одно можуть бути використані (хоча це не відповідає вимозі ОП). Це, мабуть, найпростіше продемонструвати на прикладі:

alias ssh_disc='ssh -O stop'

дозволяє мені набрати smth like ssh_disc myhost, який розширюється, як очікувалося, як:ssh -O stop myhost

Це може бути корисно для команд, які беруть складні аргументи (моя пам’ять вже не така, якою вона використовується, t не буде ...)


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. Я відредагував публікацію, щоб зробити її більш зрозумілою. Під заголовком "1. псевдонім працює, функціонує ..." Я проілюстрував, чому версія функції не працює. І, можливо, щоб відповісти на запитання безпосередньо, функція вводить нову область, де псевдонім не має.
біокіберман

Ви кажете, що це не працює, але я вам не вірю. sourceу функції працює чудово.
tripleee

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

1
BTW, повторно: використовуючи functionключове слово у своєму визначенні, див. Wiki.bash-hackers.org/scripting/obsolete - function funcname {це древній синтаксис ksh-синтаксису, який підтримує зворотну сумісність з оболонками до 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
Не потрібно створювати псевдонім функції, просто використовуйте функцію безпосередньо.
користувач3439894

1

Як вже вказували інші, використання функції слід вважати найкращою практикою.

Однак, ось ще один підхід, що використовує xargs:

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

Зауважте, що це має побічні ефекти щодо перенаправлення потоків.


0

Вам нічого не потрібно робити, псевдонім це робить автоматично.

Наприклад, якщо я хочу зробити git pull master master параметром, я можу просто створити псевдонім таким чином:

alias gpull = 'git pull origin '

і, фактично називаючи його, ви можете передавати "master" (назва гілки) як параметр, наприклад:

gpull master
//or any other branch
gpull mybranch

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