Czy utworzyć alias Bash, który przyjmuje parametr?


1270

Kiedyś używałem CShell (), który pozwala utworzyć alias, który przyjmuje parametr. Notacja była podobna

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

W Bash to nie działa. Biorąc pod uwagę, że Bash ma wiele przydatnych funkcji, zakładam, że ten został zaimplementowany, ale zastanawiam się, jak to zrobić.



2
Upewnij się, że używasz cytatów wokół argumentów"$1"
Christophe Roussy

To pytanie jest nie na temat SO. Został on odpowiedział na UNIX.SE , a odpowiedź jest taka, że nawet nie trzeba się przejmować: „Na przykład, jeśli były do aliasu lsdo ls -la, a następnie wpisując ls foo barbyłoby naprawdę wykonać ls -la foo bar. W wierszu poleceń”
Dan Dascalescu

7
to nie pomogłoby w interpolacji zmiennej w środku ciągu
Franz Sittampalam

1
Oto pseudonim testowy lil, którego użyłem do odkrycia tego błędu ... alias test_args="echo PREFIX --$1-- SUFFIX", który wywołany za pomocą test_args ABCDzwraca następujące dane wyjściowe konsoliPREFIX ---- SUFFIX ABCD
jxramos 10.10.19

Odpowiedzi:


2122

Alias ​​Bash nie akceptuje bezpośrednio parametrów. Będziesz musiał utworzyć funkcję.

aliasnie akceptuje parametrów, ale funkcję można wywołać podobnie jak alias. Na przykład:

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


myfunction old.conf new.conf #calls `myfunction`

Nawiasem mówiąc, funkcje Bash zdefiniowane w twoim .bashrci innych plikach są dostępne jako polecenia w twojej powłoce. Na przykład możesz wywołać wcześniejszą funkcję w ten sposób

$ myfunction original.conf my.conf

48
Czy powinienem zawijać $1cytaty?
Jürgen Paul

263
Nie musisz nawet deklarować aliasu. Wystarczy zdefiniowanie funkcji.
dinigo

206
Jeśli zmieniasz alias na funkcję, sourceing .bashrc doda tę funkcję, ale nie odblokuje starego aliasu. Ponieważ aliasy mają wyższy priorytet niż funkcje, spróbuje użyć aliasu. Musisz albo zamknąć i ponownie otworzyć powłokę, albo zadzwonić unalias <name>. Być może uratuję kogoś 5 minut, które właśnie zmarnowałem.
Marty Neal

55
@MartinNeal: Jedną z oszczędzających czas sztuczek, których nauczyłem się w Sun, jest po prostu exec bash: Uruchomi nową powłokę, dając ci czysty odczyt twoich konfiguracji, tak jakbyś zamknął i ponownie otworzył, ale zachował również ustawienia zmiennych środowiskowych tej sesji . Ponadto wykonywanie bashbez exec może być przydatne, gdy chcesz obsługiwać myśli jak stos.
Macneil Shonle

21
@mich - tak, zawsze umieszczaj zmienne bash w cudzysłowie. np mv "$1" "$1.bak". bez cudzysłowów, gdyby 1 $ to „hello world”, wykonałbyś mv hello world hello world.bakzamiast mv "hello world" "hello world.bak".
orion elenzil

208

Uściślając powyższą odpowiedź, możesz uzyskać 1-liniową składnię, tak jak w przypadku aliasów, co jest wygodniejsze w przypadku definicji ad-hoc w plikach powłoki lub .bashrc:

bash$ myfunction() { mv "$1" "$1.bak" && cp -i "$2" "$1"; }

bash$ myfunction original.conf my.conf

Nie zapomnij o średniku przed zamykającym prawym wspornikiem. Podobnie w przypadku rzeczywistego pytania:

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

bash$ junk() { mv "$@" ~/.Trash/; }

Lub:

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

3
Wolę tę odpowiedź, ponieważ pokazuje iterację w szeregu argumentów, które mogą się pojawić. 1 USD i 2 USD to tylko specjalne przypadki, co również ilustruje ta odpowiedź.
philo vivero

16
Zmień mv "$1" "$1.bak"; cp "$2" "$1" na, mv "$1" "$1.bak" && cp "$2" "$1"aby nie utracić danych, gdy mvwystąpią problemy (np. Pełny system plików).
Henk Langeveld

3
„Nie zapomnij o średniku przed zamykającym prawym wspornikiem.” Wiele razy to! Dzięki :)
Kaushal Modi

Wymagane są również odstępy po pierwszym nawiasie i przed ostatnim nawiasiem.
Bryan Chapel

1
@HenkLangeveld Chociaż twoja uwaga jest całkowicie poprawna, pokazuje, że byłeś przez jakiś czas w pobliżu - nie wiedziałbym, kiedy ostatni raz napotkałem błąd „brak miejsca na urządzeniu” ;-). (Używam go jednak regularnie, gdy nie znajduję już miejsca na blacie kuchennym!) Obecnie nie zdarza się to często.
Peter - przywróć Monikę

124

Pytanie jest po prostu zadawane źle. Nie tworzysz aliasu, który przyjmuje parametry, ponieważ aliaspo prostu dodaje drugą nazwę dla czegoś, co już istnieje. Funkcjonalność, jakiej chce OP, to functionpolecenie utworzenia nowej funkcji. Nie musisz aliasować funkcji, ponieważ funkcja ma już nazwę.

Myślę, że chcesz czegoś takiego:

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

Otóż ​​to! Możesz użyć parametrów 1 USD, 2 USD, 3 USD itp. Lub po prostu napełnić je wszystkie za pomocą $ @


7
Ta odpowiedź mówi wszystko. Gdybym czytał od dołu tej strony, zaoszczędziłbym trochę czasu.
Joe

-1 Alias ​​i funkcja nie są równoważne ...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

Naprawdę powinieneś zacytować $@nazwy plików ze spacjami itp.
Tom Hale

To miało być ogólne wyjaśnienie, że nie masz parametrów aliasu, zamiast tego używasz funkcji. Podana funkcja była tylko przykładem przeciwstawnym oryginalnemu przykładowi. Nie sądzę, żeby ta osoba szukała funkcji kosza na śmieci ogólnego przeznaczenia. Jednak w celu przedstawienia lepszego kodu zaktualizowałem odpowiedź.
Evan Langlois,

1
@FuzzyLogic - Spędziłem kilka minut próbując rozpakować kod w swoim komentarzu. To dużo (interesującego) wysiłku, aby przejść do spakowania kodu w komentarzu, w którym nie można go poprawnie sformatować. Nadal nie ustaliłem dokładnie, co robi ani, co ważniejsze, dlaczego obsługuje twoje (prawidłowe) stwierdzenie.
Joe

110

TL; DR: Zrób to zamiast tego

O wiele łatwiejsze i bardziej czytelne jest użycie funkcji niż aliasu do umieszczenia argumentów w środku polecenia.

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

Jeśli będziesz czytać dalej, nauczysz się rzeczy, których nie musisz wiedzieć o przetwarzaniu argumentów powłoki. Wiedza jest niebezpieczna. Po prostu uzyskaj pożądany wynik, zanim ciemna strona na zawsze kontroluje twoje przeznaczenie.

Wyjaśnienie

bashaliasy zrobić przyjąć argumenty, ale tylko na końcu :

$ alias speak=echo
$ speak hello world
hello world

Umieszczanie argumentów w środku polecenia aliasjest rzeczywiście możliwe, ale robi się brzydkie.

Nie próbuj tego w domu, dzieciaki!

Jeśli lubisz obchodzenie ograniczeń i robienie tego, co mówią inni, jest niemożliwe, oto przepis. Po prostu nie obwiniaj mnie, jeśli twoje włosy są zniszczone, a twoja twarz jest pokryta sadzą w stylu szalonego naukowca.

Obejściem tego problemu jest przekazanie argumentów, które aliasakceptują tylko na końcu, do opakowania, które wstawi je na środku, a następnie wykona polecenie.

Rozwiązanie 1

Jeśli naprawdę nie chcesz używać funkcji jako takiej, możesz użyć:

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

Można wymienić $@ze $1jeśli chcesz tylko pierwszy argument.

Wyjaśnienie 1

Tworzy to funkcję tymczasową f, do której przekazywane są argumenty (uwaga fwywoływana na samym końcu). unset -fUsuwa definicja funkcji jako alias jest wykonany tak, aby nie obijać się potem.

Rozwiązanie 2

Możesz także użyć podpowłoki:

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

Wyjaśnienie 2

Alias ​​tworzy polecenie takie jak:

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

Komentarze:

  • Element zastępczy _jest wymagany, ale może to być dowolny element. Ustawia się na sh„s” $0i jest wymagane, aby pierwszy argument podany przez użytkownika nie został wykorzystany. Demonstracja:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
  • Wymagane są pojedyncze cudzysłowy wewnątrz pojedynczych cudzysłowów. Oto przykład tego, że nie działa z podwójnymi cudzysłowami:

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

    Oto wartości interaktywna powłoka użytkownika $0i $@zastępuje się podwójnie cytowany zanim zostanie przekazany do sh. Oto dowód:

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

    Pojedyncze cudzysłowy zapewniają, że zmienne te nie są interpretowane przez interaktywną powłokę i są dosłownie przekazywane sh -c.

    Możesz użyć podwójnych cudzysłowów \$@, ale najlepszą praktyką jest zacytowanie argumentów (ponieważ mogą one zawierać spacje), i \"\$@\"wygląda jeszcze brzydiej, ale może pomóc Ci wygrać konkurs zaciemniania, w którym zwariowane włosy są warunkiem wstępnym.


2
dla rozwiązania 1, upewnij się, że używasz pojedynczych cudzysłowów i unikaj \ "około $ @. Bardzo przydatna technika, jeśli jej potrzebujesz. ty.
sgtz

Rozwiązanie 1 zadziałało dla mnie, owiń rdesktop-vrdp argumentem dla każdego serwera, który chcę.
Hsehdar

Akceptowanie argumentów na końcu jest dokładnie tym, czego potrzebowałem, aby zastąpić „git checkout {nazwa gałęzi}” prostym „gc {nazwa gałęzi}”. W .bash_profile po prostu musiałem dodaćalias gc='git checkout'
AbstractVoid

@sgtz dlaczego chcesz usunąć cytaty $@? Są one niezbędne, jeśli masz np. Pliki ze spacjami.
Tom Hale,

@TomHale To jest trochę językoznawstwo, ale rozwiązanie 1 nie jest tak naprawdę przydatne, jeśli ktoś naprawdę jest przeciwny użyciu funkcji (niezależnie od przyczyny), ponieważ bezpośrednio po przyznaniu się, że przesuwasz definicję funkcji do czasu wykonania alias. po drugie, „aliasy bash akceptują argumenty, ale tylko na końcu” to więcej semantyki: aliasy są według definicji substytucjami słów przez łańcuchy. nie muszą akceptować argumentów, jednak polecenia wykonywane przez podstawienie mogą jednak. alias jest zamiennikiem postaci, niczym więcej, niczym innym. Nie?
BUFU

39

Alternatywnym rozwiązaniem jest użycie znacznika , narzędzia, które niedawno stworzyłem, które pozwala „dodawać zakładki” do szablonów poleceń i łatwo umieszczać kursor na elementach zastępczych poleceń:

znacznik wiersza poleceń

Odkryłem, że przez większość czasu używam funkcji powłoki, więc nie muszę pisać często używanych poleceń w wierszu poleceń. Problem użycia funkcji w tym przypadku użycia polega na dodaniu nowych terminów do mojego słownika poleceń i konieczności pamiętania, jakie parametry funkcji odnoszą się do polecenia rzeczywistego. Celem markera jest wyeliminowanie tego obciążenia psychicznego.


14

Wystarczy, że utworzysz funkcję w aliasie:

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

Państwo musi umieścić w cudzysłowie „$ 1”, ponieważ apostrofów nie zadziała.


5
To sprytne, ale poza faktem, że pytanie określało, że należy utworzyć alias, czy jest jakiś powód, aby początkowo nie tworzyć funkcji o tej samej nazwie co alias?
xaxxon

1
@xaxxon Nie bardzo, ale to najłatwiejszy sposób, w jaki znam użycie aliasu, a nie funkcji.
Ken Tran

1
To nie działa. Na Ubuntu 18 pojawia się błąd bash: syntax error near unexpected token '{mkdir'.
Shital Shah

pominięcie trailing ;wewnątrz funkcji _mkcdnajprawdopodobniej z tego wynika błąd.
Jetchisel

Zostaw miejsce przed i po {i}
hesham_EE

10

Oto trzy przykłady funkcji, które mam w sobie ~/.bashrc, które są zasadniczo aliasami, które akceptują parametr:

#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
}

Bibliografia:


Co? To funkcja, a nie alias. Jednym z twoich odniesień jest właśnie to pytanie.
tripleee

2
Nie, działa dokładnie jak funkcja. Jak wyjaśnia kilka odpowiedzi tutaj, nie można utworzyć aliasu, który przyjmuje parametr. Możesz napisać funkcję, którą właśnie zrobiłeś.
tripleee

1
@tripleee Z mojego punktu widzenia początkującego użytkownika, przed przeczytaniem twojego komentarza pomyślałem, że to alias (alternatywny sposób na jego utworzenie). O ile wiem, działa dokładnie tak samo jak jeden. Jest to w istocie aliasem że przyjmuje parametr, nawet jeśli jestem off na terminologii. Nie widzę problemu. Wyjaśniłem link do innej odpowiedzi w tym problemie. Pomogło mi to stworzyć.
aliteralmind

1
Być może nie odpowiada to konkretnie na pytanie „alias bash, który akceptuje parametr”, ponieważ rozumiem teraz, że nie jest to możliwe, ale z pewnością skutecznie na nie odpowiada. Czego tu brakuje?
aliteralmind

2
Oto kilka naprawdę dobrych przykładów i ładnie skomentowany kod. Świetna pomoc dla osób odwiedzających tę stronę.
chim

9

Alias ​​Bash absolutnie akceptuje parametry. Właśnie dodałem alias, aby utworzyć nową aplikację reagującą, która akceptuje nazwę aplikacji jako parametr. Oto mój proces:

Otwórz profil bash do edycji w nano

nano /.bash_profile

Dodaj swoje aliasy, po jednym w wierszu:

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

Uwaga: „$ @” akceptuje parametry przekazane jak „creact my-new-app”

Zapisz i zamknij edytor nano

Ctrl + O, aby napisać (naciśnij Enter); ctrl + x, aby wyjść

Powiedz terminalowi, aby używał nowych aliasów w .bash_profile

source /.bash_profile

Otóż ​​to! Możesz teraz używać swoich nowych aliasów


6

Uwaga: W przypadku, gdy pomysł nie jest oczywisty, złym pomysłem jest używanie aliasów do czegokolwiek poza aliasami, z których pierwszy to „funkcja w aliasie”, a drugi to „trudne do odczytania przekierowanie / źródło”. Są też wady (które, jak sądzę , byłyby oczywiste, ale na wszelki wypadek jesteś zdezorientowany: nie mam na myśli, że można ich używać ... gdziekolwiek!)

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

Odpowiedziałem na to wcześniej i zawsze tak było w przeszłości:

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

co jest w porządku i dobre, chyba że unikasz jednoczesnego korzystania z funkcji. w takim przypadku możesz skorzystać z ogromnej możliwości przekierowania tekstu przez bash:

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

Oba są mniej więcej tej samej długości dają lub biorą kilka znaków.

Rzeczywistym kopiący jest różnica czasu, górna jest metoda „funkcja” i dolny jest metoda „przekierowanie source”. Aby udowodnić tę teorię, czas mówi sam za siebie:

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

To jest dolna część około 200 wyników, wykonywanych w przypadkowych odstępach czasu. Wygląda na to, że tworzenie / niszczenie funkcji zajmuje więcej czasu niż przekierowanie. Mam nadzieję, że pomoże to przyszłym użytkownikom tego pytania (nie chciałem tego zatrzymywać dla siebie).


2
Posiadanie aliasu definiującego funkcję, a następnie uruchomienie tej funkcji jest po prostu głupie. Po prostu napisz funkcję. W prawie każdym celu aliasy są zastępowane przez funkcje powłoki.
geirha

na wypadek, gdybyś nie przeczytał wszystkiego, co możesz spróbować, zilustrowałem, dlaczego użycie metody funkcji nie było tak dobre, a co więcej, wcale nie jest głupie. Przestań publikować i przegłosowywać tylko dlatego, że osobiście ci się nie podobało ... lub przynajmniej podaj prawidłowe wyjaśnienie. Wywołanie imienia jest pierwszym znakiem bliskości umysłu ...
osirisgothra

1
Drugi (alias słupkowy) ma kilka skutków ubocznych. Po pierwsze, polecenie nie może użyć standardowego wejścia. Po drugie, jeśli po aliasie nie podano żadnych argumentów, zamiast tego przekazywane są wszelkie argumenty powłoki. Użycie funkcji pozwala uniknąć tych wszystkich efektów ubocznych. (Również bezużyteczne użycie kota).
geirha

2
hej, nigdy nie powiedziałem, że to dobry pomysł, po prostu powiedziałem, że są też inne sposoby, aby to zrobić - główna idea polega na tym, że nie należy używać funkcji w aliasach, ponieważ są one wolniejsze niż skomplikowane przekierowanie, myślałem, że to byłoby oczywiste, ale myślę, że muszę to przeliterować dla wszystkich (na co mnie też krzyczę, że post jest zbyt rozdęty, jeśli to zrobię)
osirisgothra

1
Ponieważ czasy z baru są na 0, to podejrzewam, że powłoka nie jest czas to poprawnie. Zauważ, że komunikat o czasie jest drukowany przed uruchomieniem polecenia? Ergo, nic nie mierzy, a następnie wykonuje takt, więc w ogóle nie mierzysz taktu. Zrób coś bardziej złożonego lub dużą pętlę w takcie, abyś bardziej zrozumiałym, że nic nie
mierzyłeś

6

Jeśli szukasz ogólnego sposobu zastosowania wszystkich parametrów do funkcji, a nie tylko jednej, dwóch lub innej zakodowanej na stałe ilości, możesz to zrobić w ten sposób:

#!/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;

W powyższym przykładzie przekazuję wszystkie parametry od momentu uruchomienia runjardo aliasu.

Na przykład, gdybym runjar hi thereto zrobił , skończyłoby to faktycznie uruchomieniem java -jar myjar.jar hi there. Gdybym runjar one two threeto zrobił , uruchomiłbym się java -jar myjar.jar one two three.

Lubię to $@oparte na rozwiązaniu, ponieważ działa z dowolną liczbą parametrów.


4
dlaczego nie nazwać funkcji runjarzamiast uczynić ją aliasem funkcji? Wydaje się niepotrzebnie skomplikowane!
Evan Langlois,

Funkcje @EvanLanglois są automatycznie alias-ed (lub posiadające właściwości rzeczy przekazane alias) w plikach bash? jeśli tak, to po prostu to nie wiedziałem
Micheasza

Nie rozumiem o co ci chodzi. Alias ​​to inna nazwa, zarówno osoba, jak i funkcja. Więc stworzyłeś funkcję, a potem nadałeś jej drugą nazwę. Alias ​​nie ma nic specjalnego, jest to tylko drugie imię i nie jest wymagane. To, co wpisujesz w wierszu poleceń, może być funkcjami wewnętrznymi lub zewnętrznymi, więc „funkcja” tworzy nowe polecenie, a nie alias.
Evan Langlois,

4
To jest bezcelowe. To jest tak samo jak alias runjar='java -jar myjar.jar'. Aliasy akceptują argumenty, ale tylko na końcu.
Tom Hale

6

Z szacunkiem dla wszystkich, którzy mówią, że nie można wstawić parametru w środku aliasu, właśnie go przetestowałem i stwierdziłem, że zadziałał.

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

kiedy potem uruchomiłem mycommand foobar, działało to dokładnie tak, jakbym napisał polecenie z długim czasem.


Oczywiście, alias może uzyskać parametry, jestem w wieku przy użyciu tego, np .: alias commit = "git commit -m $ 1"
agapitocandemor

Nie działa dla mnie: alias myalias="echo 1 "$1" 3"; myalias 2daje mi:1 3 2
dirdi

4

Istnieją uzasadnione techniczne powody, aby chcieć uogólnionego rozwiązania problemu aliasu bash, który nie ma mechanizmu przejmowania arbitralnych argumentów. Jednym z powodów jest to, że na polecenie, które chcesz wykonać, miałyby negatywny wpływ zmiany środowiska wynikające z wykonania funkcji. We wszystkich innych przypadkach należy korzystać z funkcji.

To, co ostatnio zmusiło mnie do podjęcia próby rozwiązania tego, to to, że chciałem stworzyć kilka skróconych poleceń do drukowania definicji zmiennych i funkcji. Więc napisałem kilka funkcji w tym celu. Istnieją jednak pewne zmienne, które są (lub mogą być) zmieniane przez samo wywołanie funkcji. Wśród nich są:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Podstawowe polecenie, którego użyłem (w funkcji) do drukowania defns zmiennych. w postaci danych wyjściowych polecenia set:

sv () { set | grep --color=never -- "^$1=.*"; }

Na przykład:

> V=voodoo
sv V
V=voodoo

Problem: Nie spowoduje to wydrukowania wyżej wymienionych definicji zmiennych, ponieważ znajdują się one w bieżącym kontekście , np. Jeśli w interaktywnym pytaniu powłoki (lub nie w żadnym wywołaniu funkcji) FUNCNAME nie jest zdefiniowany. Ale moja funkcja mówi mi nieprawidłowe informacje:

> sv FUNCNAME
FUNCNAME=([0]="sv")

Jedno z opracowanych przeze mnie rozwiązań zostało wspomniane przez innych w innych postach na ten temat. W tym konkretnym poleceniu wypisania zmiennych defns., Które wymaga tylko jednego argumentu, zrobiłem to:

alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'

Co daje poprawne dane wyjściowe (brak) i status wyniku (false):

> asv FUNCNAME
> echo $?
1

Jednak nadal czułem się zmuszony do znalezienia rozwiązania, które zadziałałoby dla dowolnej liczby argumentów.

Ogólne rozwiązanie dotyczące przekazywania arbitralnych argumentów do polecenia aliasowego 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".

Na przykład:

> . 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

Zaletą tego rozwiązania jest to, że wszystkie specjalne sztuczki używane do obsługi parametrów pozycyjnych (argumentów) poleceń działają podczas tworzenia polecenia uwięzionego. Jedyną różnicą jest to, że należy użyć składni tablicy.

Na przykład,

Jeśli chcesz „$ @”, użyj „$ {CMD_ARGV [@]}”.

Jeśli chcesz „$ #”, użyj „$ {# CMD_ARGV [@]}”.

Itp.


3

Kiedyś zrobiłem fajny projekt i nadal go używam. Pokazuje kilka animacji podczas kopiowania plików za pomocą cppolecenia, cpponieważ nic nie pokazuje i jest to trochę frustrujące. Więc stworzyłem ten alias

alias cp="~/SCR/spiner cp"

A to jest skrypt spiner

#!/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

Tak to wygląda

wprowadź opis zdjęcia tutaj

Cykliczna animacja)

wprowadź opis zdjęcia tutaj


2

Do pobierania parametrów należy używać funkcji!

Jednak $ @ zostanie zinterpretowany podczas tworzenia aliasu zamiast podczas wykonywania aliasu i ucieczka przed $ nie działa również. Jak rozwiązać ten problem?

Aby pozbyć się tego problemu, musisz użyć funkcji powłoki zamiast aliasu. Możesz zdefiniować foo w następujący sposób:

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

LUB

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

Na koniec wywołaj foo (), używając następującej składni:

foo arg1 arg2 argN

Upewnij się, że dodajesz swoją foo () do ~/.bash_profilelub ~/.zshrcpliku.

W twoim przypadku to zadziała

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

Nie rozumiem twojego pomysłu. Myślę, że nie ma znaczenia, kiedy argumenty zostaną zinterpretowane. Alias ​​akceptuje na końcu tyle parametrów, ile chcesz.
Timo,

Ale lepiej zrobić to z funkcjami. Aliasy nie są do tego przeznaczone.
Ahmad Awais

1

Funkcje są rzeczywiście prawie zawsze odpowiedzią, jak już obszernie napisano i potwierdzone przez ten cytat ze strony podręcznika: „W prawie każdym celu aliasy są zastępowane przez funkcje powłoki”.

Dla kompletności i ponieważ może to być przydatne (nieznacznie lekka składnia), można zauważyć, że gdy parametr (y) podążają za aliasem, mogą być nadal używane (chociaż nie spełniałoby wymagań OP). Prawdopodobnie najłatwiej to wykazać na przykładzie:

alias ssh_disc='ssh -O stop'

pozwala mi pisać coś podobnego ssh_disc myhost, który jest rozwijany zgodnie z oczekiwaniami:ssh -O stop myhost

Może to być przydatne w przypadku poleceń, które przyjmują złożone argumenty (moja pamięć nie jest już tym, czego używa ...


1

Zarówno funkcje, jak i aliasy mogą wykorzystywać parametry, jak pokazali tutaj inni. Dodatkowo chciałbym zwrócić uwagę na kilka innych aspektów:

1. funkcja działa we własnym zakresie, alias dzieli zakres

Warto znać tę różnicę, gdy musisz coś ukryć lub ujawnić. Sugeruje również, że funkcja jest lepszym wyborem do enkapsulacji.

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 

Wynik:

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. skrypt otoki jest lepszym wyborem

Kilkakrotnie zdarzyło mi się, że nie można znaleźć aliasu lub funkcji podczas logowania przezssh lub przy zmianie nazwy użytkownika lub środowiska dla wielu użytkowników. Istnieją wskazówki i triki dotyczące plików kropek lub ten interesujący z aliasem: alias sd='sudo 'pozwala, aby ten kolejny alias alias install='sd apt-get install'działał zgodnie z oczekiwaniami (zwróć uwagę na dodatkowe miejsce sd='sudo '). Jednak w takich przypadkach skrypt opakowujący działa lepiej niż funkcja lub alias. Główną zaletą skryptu opakowującego jest to, że jest widoczny / wykonywalny pod zamierzoną ścieżką (tj. / Usr / loca / bin /), gdzie jako funkcję / alias należy uzyskać źródło, zanim będzie można go użyć. Na przykład wstawiasz funkcję do ~ / .bash_profile lub ~ / .bashrc dla bash, ale później przełączasz na inną powłokę (tj.zsh), to funkcja nie jest już widoczna. W razie wątpliwości skrypt opakowania jest zawsze najbardziej niezawodnym i przenośnym rozwiązaniem.


1
Jak myślisz, dlaczego wersja funkcji nie działa?
tripleee

@tripleee. Zredagowałem post, aby był bardziej czytelny. Pod nagłówkiem „1. alias działa, funkcja ...” zilustrowałem, dlaczego wersja funkcji nie działa. Być może, aby bezpośrednio odpowiedzieć na pytanie, funkcja wprowadza nowy zakres, w którym nie ma aliasu.
biocyberman

Mówisz, że to nie działa, ale ja ci nie wierzę. sourcew funkcji działa dobrze.
tripleee

1
f () { source /tmp/nst; }robi dokładnie to, czego oczekuję. Może twój PATHbłąd jest niewłaściwy, więc działa źle activatelub coś; ale uruchamianie sourcez funkcji działa dobrze.
tripleee

1
BTW, re: używając functionsłowa kluczowego w swojej definicji, patrz wiki.bash-hackers.org/scripting/obsolete - function funcname {jest starą składnią kash bash obsługującą wsteczną kompatybilność z powłokami sprzed POSIX, podczas gdy funcname() {jest to oficjalna składnia standaryzowana przez POSIX. function funcname() {to niedopasowanie tych dwóch, które nie jest kompatybilne ze starożytnym ksh lub kompatybilne z POSIX sh, i dlatego najlepiej go unikać.
Charles Duffy

1

Oto przykład:

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

Bardzo ważne:

  1. Jest to przestrzeń po {i przed }.
  2. ;Po każdym poleceniu jest po kolei. Jeśli zapomnisz o tym po ostatnim poleceniu, >zamiast tego zobaczysz monit!
  3. Argument jest ujęty w cudzysłów jako "$1"

2
Nie ma potrzeby tworzenia aliasu dla funkcji, wystarczy użyć funkcji bezpośrednio.
user3439894

1

Jak już zauważyli inni, korzystanie z funkcji należy uznać za najlepszą praktykę.

Oto jednak inne podejście, wykorzystujące xargs:

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

Pamiętaj, że ma to skutki uboczne dotyczące przekierowywania strumieni.


0

Nic nie musisz robić, alias robi to automatycznie.

Na przykład, jeśli chcę sparametryzować master git pull origin, mogę po prostu utworzyć alias w następujący sposób:

alias gpull = 'git pull origin '

a podczas wywoływania go jako parametr możesz przekazać „master” (nazwa gałęzi):

gpull master
//or any other branch
gpull mybranch

To nie odpowiada na pytanie, ponieważ argument nie może być umieszczony swobodnie, ale tylko na końcu.
dirdi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.