Einen Bash-Alias ​​erstellen, der einen Parameter akzeptiert?


1271

Ich habe früher CShell verwendet (), mit dem Sie einen Alias ​​erstellen können, der einen Parameter akzeptiert. Die Notation war so etwas wie

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

In Bash scheint dies nicht zu funktionieren. Angesichts der Tatsache, dass Bash eine Vielzahl nützlicher Funktionen bietet, würde ich davon ausgehen, dass diese implementiert wurde, aber ich frage mich, wie.



2
Stellen Sie sicher, dass Sie Anführungszeichen um die Argumente verwenden"$1"
Christophe Roussy

Diese Frage ist für SO nicht zum Thema. Es wurde auf UNIX.SE beantwortet , und die Antwort ist , dass Sie nicht einmal die Mühe müssen: „Zum Beispiel, wenn Sie alias waren lszu ls -la, dann mit der Eingabe ls foo barwürde wirklich ausführen ls -la foo bar. Auf der Kommandozeile“
Dan Dascalescu

7
das würde nicht helfen, eine Variable in die Mitte eines Strings zu interpolieren
Franz Sittampalam

1
Hier ist der kleine Test-Alias, mit dem ich diesen Irrtum entdeckt habe ... alias test_args="echo PREFIX --$1-- SUFFIX"der beim Aufruf mit test_args ABCDdie folgende Konsolenausgabe liefertPREFIX ---- SUFFIX ABCD
jxramos

Antworten:


2122

Der Bash-Alias ​​akzeptiert Parameter nicht direkt. Sie müssen eine Funktion erstellen.

aliasakzeptiert keine Parameter, aber eine Funktion kann wie ein Alias ​​aufgerufen werden. Zum Beispiel:

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


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

Bash-Funktionen, die in Ihren .bashrcund anderen Dateien definiert sind, stehen übrigens als Befehle in Ihrer Shell zur Verfügung. So können Sie beispielsweise die frühere Funktion so aufrufen

$ myfunction original.conf my.conf

48
Soll ich $1in Anführungszeichen setzen?
Jürgen Paul

263
Sie müssen nicht einmal den Alias ​​deklarieren. Nur die Definition der Funktion reicht aus.
Dinigo

207
Wenn Sie einen Alias ​​in eine Funktion sourceändern, fügt Ihre .bashrc-Funktion die Funktion hinzu, der alte Alias ​​wird jedoch nicht unaliasiert. Da Aliase einen höheren Präzedenzfall als Funktionen haben, wird versucht, den Alias ​​zu verwenden. Sie müssen entweder Ihre Shell schließen und erneut öffnen oder aufrufen unalias <name>. Vielleicht spare ich jemandem die 5 Minuten, die ich gerade verschwendet habe.
Marty Neal

55
@MartinNeal: Ein zeitsparender Trick, den ich bei Sun gelernt habe, besteht darin, einfach Folgendes zu tun exec bash: Es wird eine neue Shell gestartet, mit der Sie Ihre Konfigurationen sauber lesen können, als ob Sie sie geschlossen und wieder geöffnet hätten, aber auch die Umgebungsvariableneinstellungen dieser Sitzung beibehalten . Das Ausführen bashohne exec kann auch nützlich sein, wenn Sie Gedanken wie einen Stapel behandeln möchten.
Macneil Shonle

21
@mich - ja, immer Bash-Variablen in Anführungszeichen setzen. zB mv "$1" "$1.bak". Wenn $ 1 ohne Anführungszeichen "Hallo Welt" wäre, würden Sie mv hello world hello world.bakstattdessen ausführen mv "hello world" "hello world.bak".
Orion Elenzil

208

Wenn Sie die obige Antwort verfeinern, erhalten Sie eine einzeilige Syntax wie für Aliase. Dies ist praktischer für Ad-hoc-Definitionen in einer Shell oder in .bashrc-Dateien:

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

bash$ myfunction original.conf my.conf

Vergessen Sie nicht das Semikolon vor der schließenden rechten Klammer. Ebenso für die eigentliche Frage:

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

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

Oder:

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

3
Ich bevorzuge diese Antwort, da sie das Durchlaufen der Reihe von Argumenten zeigt, die möglicherweise eingehen. $ 1 und $ 2 sind nur Sonderfälle, die auch in dieser Antwort dargestellt werden.
Philo Vivero

16
Wechseln Sie mv "$1" "$1.bak"; cp "$2" "$1" zu mv "$1" "$1.bak" && cp "$2" "$1", um Ihre Daten nicht zu verlieren, wenn mvProbleme auftreten (z. B. Dateisystem voll).
Henk Langeveld

3
"Vergessen Sie nicht das Semikolon vor der schließenden rechten Klammer." Oft das! Danke :)
Kaushal Modi

Und die Leerzeichen nach der ersten Klammer und vor der letzten Klammer sind ebenfalls erforderlich.
Bryan Chapel

1
@HenkLangeveld Obwohl Ihre Bemerkung vollkommen korrekt ist, zeigt sie, dass Sie schon eine Weile da sind - ich würde nicht wissen, wann ich das letzte Mal auf den Fehler "Kein Platz mehr auf dem Gerät" gestoßen bin ;-). (Ich benutze es jedoch regelmäßig, wenn ich keinen Platz mehr auf der Küchentheke finde!) Scheint heutzutage nicht sehr oft zu passieren.
Peter - Monica

124

Die Frage wird einfach falsch gestellt. Sie erstellen keinen Alias, der Parameter akzeptiert, da aliasnur ein zweiter Name für etwas hinzugefügt wird, das bereits vorhanden ist. Die vom OP gewünschte Funktionalität ist der functionBefehl zum Erstellen einer neuen Funktion. Sie müssen die Funktion nicht aliasen, da die Funktion bereits einen Namen hat.

Ich denke du willst so etwas:

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

Das ist es! Sie können die Parameter $ 1, $ 2, $ 3 usw. verwenden oder sie alle mit $ @ füllen


7
Diese Antwort sagt alles. Wenn ich am Ende dieser Seite gelesen hätte, hätte ich etwas Zeit gespart.
Joe

-1 Ein Alias ​​und eine Funktion sind nicht äquivalent ...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

Sie sollten wirklich zitieren $@, um Dateinamen mit Leerzeichen usw. zu unterstützen
Tom Hale

Es sollte eine allgemeine Erklärung sein, dass Sie keine Alias-Parameter haben, sondern stattdessen eine Funktion verwenden. Die angegebene Funktion war nur ein Beispiel, um dem ursprünglichen Beispiel entgegenzuwirken. Ich glaube nicht, dass die Person nach einer allgemeinen Müllfunktion gesucht hat. Um jedoch besseren Code zu präsentieren, habe ich die Antwort aktualisiert.
Evan Langlois

1
@FuzzyLogic - Ich habe einige Minuten damit verbracht, den Code in Ihrem Kommentar zu entpacken. Das ist eine Menge (interessanter) Aufwand, um Code in einen Kommentar zu packen, in dem Sie ihn nicht richtig formatieren können. Ich habe immer noch nicht genau herausgefunden, was es tut oder, was noch wichtiger ist, warum es Ihre (richtige) Behauptung unterstützt.
Joe

110

TL; DR: Tun Sie dies stattdessen

Es ist viel einfacher und lesbarer, eine Funktion als einen Alias ​​zu verwenden, um Argumente in die Mitte eines Befehls zu setzen.

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

Wenn Sie weiterlesen, lernen Sie Dinge, die Sie über die Verarbeitung von Shell-Argumenten nicht wissen müssen. Wissen ist gefährlich. Holen Sie sich einfach das gewünschte Ergebnis, bevor die dunkle Seite Ihr Schicksal für immer kontrolliert.

Klärung

bashAliase tun Argumente akzeptieren, aber erst am Ende :

$ alias speak=echo
$ speak hello world
hello world

Es ist zwar möglich, Argumente über in die Mitte des Befehls zu setzen alias, aber es wird hässlich.

Versuchen Sie das nicht zu Hause, Kinder!

Wenn Sie gerne Einschränkungen umgehen und das tun möchten, was andere sagen, ist dies unmöglich. Hier ist das Rezept. Beschuldigen Sie mich nur nicht, wenn Ihr Haar durcheinander gerät und Ihr Gesicht mit Ruß bedeckt ist.

Die Problemumgehung besteht darin, die Argumente, aliasdie nur am Ende akzeptiert werden, an einen Wrapper zu übergeben, der sie in die Mitte einfügt und dann Ihren Befehl ausführt.

Lösung 1

Wenn Sie wirklich gegen die Verwendung einer Funktion an sich sind, können Sie Folgendes verwenden:

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

Sie können ersetzen $@mit , $1wenn Sie das erste Argument wollen.

Erklärung 1

Dadurch wird eine temporäre Funktion erstellt f, der die Argumente übergeben werden (Anmerkung, fdie ganz am Ende aufgerufen wird). Das unset -fentfernt die Funktionsdefinition, wenn der Alias ​​ausgeführt wird, damit er danach nicht herumhängt.

Lösung 2

Sie können auch eine Unterschale verwenden:

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

Erklärung 2

Der Alias ​​erstellt einen Befehl wie:

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

Bemerkungen:

  • Der Platzhalter _ist erforderlich, kann aber beliebig sein. Es wird auf sh's gesetzt $0und ist erforderlich, damit das erste der vom Benutzer angegebenen Argumente nicht verbraucht wird. Demonstration:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
    
  • Die einfachen Anführungszeichen in einfachen Anführungszeichen sind erforderlich. Hier ist ein Beispiel dafür, dass es nicht mit doppelten Anführungszeichen funktioniert:

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

    Hier werden die Werte der interaktiven Shell $0und $@in die doppelte Anführungszeichen ersetzt, bevor sie an übergeben werden sh. Hier ist der Beweis:

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

    Die einfachen Anführungszeichen stellen sicher, dass diese Variablen nicht von der interaktiven Shell interpretiert und buchstäblich an übergeben werden sh -c.

    Sie könnten doppelte Anführungszeichen und verwenden \$@, aber die beste Vorgehensweise besteht darin, Ihre Argumente zu zitieren (da sie Leerzeichen enthalten können) und \"\$@\"noch hässlicher aussieht, aber Ihnen dabei helfen kann, einen Verschleierungswettbewerb zu gewinnen, bei dem zerzaustes Haar eine Voraussetzung für die Teilnahme ist.


2
Stellen Sie für Lösung 1 sicher, dass Sie einfache Anführungszeichen verwenden, und vermeiden Sie "um das $ @". Eine sehr nützliche Technik, wenn Sie sie benötigen. ty.
sgtz

Lösung 1 funktionierte für mich, um rdesktop-vrdp mit Argumenten für jeden gewünschten Server zu versehen.
Hsehdar

Das Akzeptieren von Argumenten am Ende war genau das, was ich brauchte, um "git checkout {branchname}" durch ein einfaches "gc {branchname}" zu ersetzen. In .bash_profile musste ich einfach hinzufügenalias gc='git checkout'
AbstractVoid

@sgtz warum sollten Sie Anführungszeichen entfernen wollen $@? Sie sind erforderlich, wenn Sie beispielsweise Dateien mit Leerzeichen haben.
Tom Hale

@TomHale Dies ist etwas linguistisch, aber Lösung 1 ist nicht wirklich nützlich, wenn jemand wirklich gegen die Verwendung einer Funktion ist (aus welchem ​​Grund auch immer), da Sie sich direkt eingestehen, dass Sie die Definition einer Funktion nur auf die Ausführungszeit von verschieben der Alias. Zweitens ist "Bash-Aliase akzeptieren Argumente, aber nur am Ende" mehr Semantik: Aliase sind per Definition Substitutionen von Wörtern durch Zeichenfolgen. Sie müssen keine Argumente akzeptieren, die Befehle, die über die Substitution ausgeführt werden, können dies jedoch. Alias ​​ist ein Zeichenersatz, nicht mehr und nicht weniger. Nein?
BUFU

39

Eine alternative Lösung ist die Verwendung von marker , einem kürzlich von mir erstellten Tool, mit dem Sie Befehlsvorlagen mit einem Lesezeichen versehen und den Cursor einfach auf Befehlsplatzhalter setzen können:

Befehlszeilenmarkierung

Ich habe festgestellt, dass ich die meiste Zeit Shell-Funktionen verwende, damit ich nicht immer wieder häufig verwendete Befehle in die Befehlszeile schreiben muss. Das Problem bei der Verwendung von Funktionen für diesen Anwendungsfall besteht darin, meinem Befehlsvokabular neue Begriffe hinzuzufügen und sich daran zu erinnern, auf welche Funktionsparameter sich im Real-Befehl beziehen. Marker Ziel ist es, diese mentale Belastung zu beseitigen.


14

Alles was Sie tun müssen, ist eine Funktion innerhalb eines Alias ​​zu erstellen:

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

Sie müssen doppelte Anführungszeichen um "$ 1" setzen, da einfache Anführungszeichen nicht funktionieren.


5
Das ist klug, aber abgesehen von der Tatsache, dass in der Frage angegeben wurde, einen Alias ​​zu erstellen, gibt es einen Grund, die Funktion nicht einfach mit demselben Namen wie der ursprüngliche Alias ​​zu erstellen?
Xaxxon

1
@xaxxon Nicht wirklich, aber es ist der einfachste Weg, einen Alias ​​zu verwenden, keine Funktion.
Ken Tran

1
Das funktioniert nicht. Unter Ubuntu 18 wird eine Fehlermeldung angezeigt bash: syntax error near unexpected token '{mkdir'.
Shital Shah

Fehlt ein Trailing ;innerhalb der Funktion, liegt _mkcdder Fehler höchstwahrscheinlich daran.
Jetchisel

Lassen Sie vor und nach dem {und}
hesham_EE

10

Hier sind drei Beispiele für Funktionen, die ich in meinem habe ~/.bashrc, im Wesentlichen Aliase, die einen Parameter akzeptieren:

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

Verweise:


Huh? Das ist eine Funktion, kein Alias. Und eine Ihrer Referenzen ist genau diese Frage.
Tripleee

2
Nein, es funktioniert genau wie eine Funktion. Wie einige der Antworten hier erklären, können Sie keinen Alias ​​erstellen, der einen Parameter akzeptiert. Was Sie tun können, ist eine Funktion zu schreiben, die Sie getan haben.
Tripleee

1
@tripleee Aus der Sicht meines Bash-Neulings dachte ich vor dem Lesen Ihres Kommentars, es sei ein Alias ​​(eine alternative Möglichkeit, einen zu erstellen). Es funktioniert genau wie eins, soweit ich das beurteilen kann. Es ist im Wesentlichen ein Alias, der einen Parameter akzeptiert, auch wenn ich mit der Terminologie nicht einverstanden bin. Ich sehe das Problem nicht. Ich habe den Link zur anderen Antwort in diesem Problem geklärt. Es hat mir geholfen, dies zu schaffen.
Aliteralmind

1
Vielleicht beantwortet dies nicht speziell die Frage nach einem "Bash-Alias, der einen Parameter akzeptiert", weil ich jetzt verstehe, dass dies nicht möglich ist, aber es beantwortet es auf jeden Fall effektiv . Was fehlt mir hier?
Aliteralmind

2
Einige wirklich gute Beispiele hier und gut kommentierter Code. Eine große Hilfe für die Leute, die auf diese Seite kommen.
chim

9

Der Bash-Alias ​​akzeptiert absolut keine Parameter. Ich habe gerade einen Alias ​​hinzugefügt, um eine neue Reaktions-App zu erstellen, die den App-Namen als Parameter akzeptiert. Hier ist mein Prozess:

Öffnen Sie das bash_profile zur Bearbeitung in nano

nano /.bash_profile

Fügen Sie Ihre Aliase hinzu, einen pro Zeile:

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

Hinweis: Das "$ @" akzeptiert übergebene Parameter wie "creact my-new-app".

Speichern und beenden Sie den Nano-Editor

Strg + O zum Schreiben (drücken Sie die Eingabetaste); Strg + x zum Beenden

Weisen Sie das Terminal an, die neuen Aliase in .bash_profile zu verwenden

source /.bash_profile

Das ist es! Sie können jetzt Ihre neuen Aliase verwenden


6

NB: Falls die Idee nicht offensichtlich ist, ist es eine schlechte Idee, Aliase für alles andere als Aliase zu verwenden, wobei der erste die "Funktion in einem Alias" und der zweite die "schwer lesbare Weiterleitung / Quelle" ist. Es gibt auch Mängel (die ich für offensichtlich hielt, aber nur für den Fall, dass Sie verwirrt sind: Ich meine nicht, dass sie tatsächlich verwendet werden sollen ... überall!)

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

Ich habe das schon einmal beantwortet und es war in der Vergangenheit immer so:

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

Das ist in Ordnung und gut, es sei denn, Sie vermeiden die Verwendung von Funktionen insgesamt. In diesem Fall können Sie die umfassende Fähigkeit von bash nutzen, Text umzuleiten:

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

Sie sind beide ungefähr gleich lang und geben oder nehmen ein paar Zeichen.

Der eigentliche Kicker ist der Zeitunterschied, wobei die obere die "Funktionsmethode" und die untere die "Redirect-Source" -Methode ist. Um diese Theorie zu beweisen, spricht das Timing für sich:

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

Dies ist der untere Teil von ungefähr 200 Ergebnissen, die in zufälligen Intervallen durchgeführt werden. Es scheint, dass die Erstellung / Zerstörung von Funktionen mehr Zeit in Anspruch nimmt als die Umleitung. Hoffentlich hilft dies zukünftigen Besuchern bei dieser Frage (wollte sie nicht für mich behalten).


2
Einen Alias ​​zu haben, der eine Funktion definiert, und diese Funktion dann auszuführen, ist einfach albern. Schreiben Sie einfach eine Funktion. Für fast jeden Zweck werden Aliase durch Shell-Funktionen ersetzt.
Geirha

Für den Fall, dass Sie nicht alles gelesen haben, was Sie vielleicht versuchen, habe ich veranschaulicht, warum die Verwendung der Funktionsmethode überhaupt nicht so gut war und außerdem überhaupt nicht albern. Hören Sie auf zu posten und abzustimmen, nur weil es Ihnen persönlich nicht gefallen hat ... oder geben Sie zumindest eine gültige Erklärung.
Namensnennung

1
Der zweite (der Balkenalias) hat mehrere Nebenwirkungen. Erstens kann der Befehl stdin nicht verwenden. Zweitens, wenn nach dem Alias ​​keine Argumente angegeben werden, werden stattdessen alle Argumente übergeben, die die Shell zufällig hat. Durch die Verwendung einer Funktion werden all diese Nebenwirkungen vermieden. (Auch nutzlose Verwendung von Katze).
Geirha

2
Hey, ich habe nie gesagt, dass es eine gute Idee ist, dies zu tun. Ich habe nur gesagt, dass es auch andere Möglichkeiten gibt, dies zu tun. Die Hauptidee hier ist, dass Sie keine Funktionen in Aliasen verwenden sollten, da diese sogar langsamer als kompliziert sind Umleitung, ich dachte, das wäre offensichtlich gewesen, aber ich denke, ich muss es für alle
formulieren

1
Da die Timings der Balken alle Nullen sind, würde ich vermuten, dass die Shell dies nicht richtig timt. Beachten Sie, dass die Zeitnachricht gedruckt wird, bevor der Befehl ausgeführt wird. Ergo, es mal nichts und führt dann einen Balken durch, so dass Sie den Balken überhaupt nicht messen. Machen Sie etwas komplexeres oder eine große Schleife in der Leiste, damit Sie klarer machen können, dass Sie nichts
Evan Langlois

6

Wenn Sie nach einer generischen Möglichkeit suchen, alle Parameter auf eine Funktion anzuwenden, nicht nur auf eine oder zwei oder eine andere fest codierte Menge, können Sie dies folgendermaßen tun:

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

Im obigen Beispiel übergebe ich alle Parameter von der Ausführung runjaran den Alias.

Wenn ich runjar hi therees zum Beispiel tun würde, würde es tatsächlich laufen java -jar myjar.jar hi there. Wenn ich es tun runjar one two threewürde, würde es laufen java -jar myjar.jar one two three.

Ich mag diese $@basierte Lösung, weil sie mit einer beliebigen Anzahl von Parametern funktioniert.


4
Warum nicht einfach die Funktion benennen, runjaranstatt sie zu einem Alias ​​für eine Funktion zu machen? Scheint unnötig kompliziert!
Evan Langlois

@ EvansLanglois-Funktionen werden in Bash-Dateien automatisch alias-ed (oder haben die Eigenschaften von Dingen übergeben alias)? Wenn ja, dann habe ich das einfach nicht gewusst
Micah

Verstehe nicht was du meinst. Ein Alias ​​ist ein anderer Name, sei es eine Person oder eine Funktion. Sie haben also eine Funktion erstellt und dann einen zweiten Namen für die Funktion erstellt. Der Alias ​​hat nichts Besonderes, er ist nur ein zweiter Name und nicht erforderlich. Was Sie in die Befehlszeile eingeben, können interne oder externe Funktionen sein. "Funktion" erstellt also einen neuen Befehl, keinen Alias.
Evan Langlois

4
Das ist sinnlos. Es ist das gleiche wie alias runjar='java -jar myjar.jar'. Aliase akzeptieren Argumente, aber nur am Ende.
Tom Hale

6

Mit Respekt vor allen, die sagen, dass Sie keinen Parameter in die Mitte eines Alias ​​einfügen können, habe ich ihn gerade getestet und festgestellt, dass er funktioniert hat.

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

Als ich dann mycommand foobar ausführte, funktionierte es genau so, als hätte ich den Befehl lang geschrieben.


Absolut, Alias ​​kann Parameter bekommen, ich benutze dieses Alter, zB: alias commit = "git commit -m $ 1"
agapitocandemor

Funktioniert bei mir nicht: alias myalias="echo 1 "$1" 3"; myalias 2gibt mir:1 3 2
dirdi

4

Es gibt legitime technische Gründe, eine allgemeine Lösung für das Problem des Bash-Alias ​​zu wollen, der keinen Mechanismus hat, um willkürliche Argumente neu zu positionieren. Ein Grund ist, wenn der Befehl, den Sie ausführen möchten, durch die Änderungen an der Umgebung, die sich aus der Ausführung einer Funktion ergeben, beeinträchtigt wird. In allen anderen Fällen sollten Funktionen verwendet werden.

Was mich kürzlich dazu gezwungen hat, eine Lösung dafür zu finden, ist, dass ich einige abgekürzte Befehle zum Drucken der Definitionen von Variablen und Funktionen erstellen wollte. Deshalb habe ich einige Funktionen für diesen Zweck geschrieben. Es gibt jedoch bestimmte Variablen, die durch einen Funktionsaufruf selbst geändert werden (oder werden können). Unter ihnen sind:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Der grundlegende Befehl, den ich (in einer Funktion) zum Drucken von Variablendefinitionen verwendet hatte. In der vom Befehl set ausgegebenen Form war:

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

Z.B:

> V=voodoo
sv V
V=voodoo

Problem: Dadurch werden die Definitionen der oben genannten Variablen nicht gedruckt, da sie sich im aktuellen Kontext befinden , z. B. wenn in einer interaktiven Shell-Eingabeaufforderung (oder nicht in Funktionsaufrufen) FUNCNAME nicht definiert ist. Aber meine Funktion sagt mir die falschen Informationen:

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

Eine Lösung, die ich gefunden habe, wurde von anderen in anderen Beiträgen zu diesem Thema erwähnt. Für diesen speziellen Befehl zum Drucken von Variablendefinitionen, für den nur ein Argument erforderlich ist, habe ich Folgendes getan:

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

Welches gibt die richtige Ausgabe (keine) und Ergebnisstatus (falsch):

> asv FUNCNAME
> echo $?
1

Ich fühlte mich jedoch immer noch gezwungen, eine Lösung zu finden, die für eine beliebige Anzahl von Argumenten funktioniert.

Eine allgemeine Lösung zum Übergeben beliebiger Argumente an einen Bash-Alias-Befehl:

# (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".

Z.B:

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

Eine schöne Sache an dieser Lösung ist, dass alle speziellen Tricks, die zum Behandeln von Positionsparametern (Argumenten) für Befehle verwendet werden, beim Erstellen des eingeschlossenen Befehls funktionieren. Der einzige Unterschied besteht darin, dass die Array-Syntax verwendet werden muss.

Z.B,

Wenn Sie "$ @" möchten, verwenden Sie "$ {CMD_ARGV [@]}".

Wenn Sie "$ #" möchten, verwenden Sie "$ {# CMD_ARGV [@]}".

Usw.


3

Einmal habe ich ein lustiges Projekt gemacht und ich benutze es immer noch. Es zeigt einige Animationen, während ich Dateien über den cpBefehl kopiere cp, weil nichts angezeigt wird und es irgendwie frustrierend ist. Also habe ich diesen Alias ​​gemacht

alias cp="~/SCR/spiner cp"

Und das ist das Spiner-Skript

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

Es sieht so aus

Geben Sie hier die Bildbeschreibung ein

Fahrradanimation)

Geben Sie hier die Bildbeschreibung ein


2

Zum Aufnehmen von Parametern sollten Sie Funktionen verwenden!

Allerdings wird $ @ beim Erstellen des Alias ​​nicht während der Ausführung des Alias ​​interpretiert, und das Escapezeichen für $ funktioniert auch nicht. Wie löse ich dieses Problem?

Sie müssen die Shell-Funktion anstelle eines Alias ​​verwenden, um dieses Problem zu beheben. Sie können foo wie folgt definieren:

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

ODER

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

Rufen Sie abschließend Ihr foo () mit der folgenden Syntax auf:

foo arg1 arg2 argN

Stellen Sie sicher, dass Sie Ihr foo () ~/.bash_profileoder Ihre ~/.zshrcDatei hinzufügen .

In Ihrem Fall wird dies funktionieren

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

Ich verstehe deine Idee nicht. Ich denke, es ist nicht wichtig, wann die Argumente interpretiert werden. Aliase akzeptiert am Ende so viele Parameter, wie Sie möchten.
Timo

Aber es ist besser, das mit Funktionen zu tun. Aliase sind dafür nicht gedacht.
Ahmad Awais

1

Funktionen sind in der Tat fast immer die Antwort, da dieses Zitat aus der Manpage bereits reichlich dazu beigetragen und bestätigt hat: "Für fast jeden Zweck werden Aliase durch Shell-Funktionen ersetzt."

Der Vollständigkeit halber und weil dies nützlich sein kann (geringfügig leichtere Syntax), kann angemerkt werden, dass die Parameter, wenn sie dem Alias ​​folgen, weiterhin verwendet werden können (obwohl dies die Anforderungen des OP nicht erfüllen würde). Dies lässt sich wahrscheinlich am einfachsten anhand eines Beispiels demonstrieren:

alias ssh_disc='ssh -O stop'

erlaubt mir, etw wie zu tippen ssh_disc myhost, das wie erwartet erweitert wird als:ssh -O stop myhost

Dies kann nützlich sein für Befehle, die komplexe Argumente annehmen (mein Gedächtnis ist nicht mehr das, was er verwendet ...).


1

Sowohl Funktionen als auch Aliase können Parameter verwenden, wie andere hier gezeigt haben. Darüber hinaus möchte ich auf einige andere Aspekte hinweisen:

1. Die Funktion wird in einem eigenen Bereich ausgeführt, der Alias ​​teilt den Bereich

Es kann nützlich sein, diesen Unterschied zu kennen, wenn Sie etwas verstecken oder bloßstellen müssen. Dies legt auch nahe, dass eine Funktion die bessere Wahl für die Kapselung ist.

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 

Ausgabe:

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. Wrapper-Skript ist eine bessere Wahl

Es ist mir mehrmals passiert, dass ein Alias ​​oder eine Funktion nicht gefunden werden kann, wenn Sie sich über einenssh Benutzernamen oder eine Mehrbenutzerumgebung anmelden oder diesen wechseln. Es gibt Tipps und Tricks zum Beschaffen von Punktdateien oder diese interessante mit Alias: alias sd='sudo 'Lässt diesen nachfolgenden Alias alias install='sd apt-get install'wie erwartet funktionieren (beachten Sie den zusätzlichen Speicherplatz in sd='sudo '). In solchen Fällen funktioniert ein Wrapper-Skript jedoch besser als eine Funktion oder ein Alias. Der Hauptvorteil eines Wrapper-Skripts besteht darin, dass es unter dem beabsichtigten Pfad (dh / usr / loca / bin /) sichtbar / ausführbar ist, wobei eine Funktion / ein Alias ​​bereitgestellt werden muss, bevor es verwendet werden kann. Zum Beispiel setzen Sie eine Funktion in ein ~ / .bash_profile oder ~ / .bashrc für bash, wechseln aber später zu einer anderen Shell (dhzsh) dann ist die Funktion nicht mehr sichtbar. Wenn Sie Zweifel haben, ist ein Wrapper-Skript immer die zuverlässigste und portabelste Lösung.


1
Warum funktioniert die Funktionsversion Ihrer Meinung nach nicht?
Tripleee

@ Tripleee. Ich habe den Beitrag bearbeitet, um ihn besser lesbar zu machen. Unter der Überschrift "1. Alias ​​funktioniert, Funktion ..." habe ich gezeigt, warum eine Funktionsversion nicht funktioniert. Und um die Frage direkt zu beantworten, führt function einen neuen Bereich ein, in dem Alias ​​dies nicht tut.
Biocyberman

Sie sagen, es funktioniert nicht, aber ich glaube Ihnen nicht. sourcein einer Funktion funktioniert gut.
Tripleee

1
f () { source /tmp/nst; }macht genau das, was ich erwarte. Vielleicht ist dein PATHfalsch, also läuft es falsch activateoder so; Das Ausführen sourceeiner Funktion funktioniert jedoch einwandfrei.
Tripleee

1
Übrigens: Verwenden Sie das functionSchlüsselwort in Ihrer Definition, siehe wiki.bash-hackers.org/scripting/obsolete - function funcname {ist eine alte ksh-Syntax, die Bash unterstützt, um die Abwärtskompatibilität mit Pre-POSIX-Shells zu gewährleisten, während funcname() {es sich um eine offizielle POSIX-standardisierte Syntax handelt. function funcname() {ist ein Missverhältnis der beiden, das nicht mit dem alten ksh oder mit POSIX sh kompatibel ist und daher am besten vermieden wird.
Charles Duffy

1

Hier ist das Beispiel:

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

Sehr wichtig:

  1. Es gibt ein Leerzeichen nach {und vor }.
  2. Es gibt einen ;nach jedem Befehl in Folge. Wenn Sie dies nach dem letzten Befehl vergessen, wird >stattdessen eine Eingabeaufforderung angezeigt!
  3. Das Argument steht in Anführungszeichen als "$1"

2
Es ist nicht erforderlich, einen Alias ​​für eine Funktion zu erstellen. Verwenden Sie die Funktion einfach direkt.
user3439894

1

Wie bereits von anderen erwähnt, sollte die Verwendung einer Funktion als bewährte Methode angesehen werden.

Hier ist jedoch ein anderer Ansatz, der Folgendes nutzt xargs:

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

Beachten Sie, dass dies Nebenwirkungen hinsichtlich der Umleitung von Streams hat.


0

Sie müssen nichts tun, Alias ​​erledigt dies automatisch.

Wenn ich beispielsweise den Git-Pull-Ursprungsmaster parametrisieren möchte, kann ich einfach einen Alias ​​wie folgt erstellen:

alias gpull = 'git pull origin '

und wenn Sie es tatsächlich aufrufen, können Sie 'master' (den Zweignamen) als Parameter übergeben, wie folgt:

gpull master
//or any other branch
gpull mybranch

Dies beantwortet die Frage nicht, da das Argument nicht frei platziert werden kann, sondern nur am Ende.
Dirdi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.