Frage Machen Sie einen Bash-Alias, der einen Parameter akzeptiert?


Ich benutzte CShell (), 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 das nicht zu funktionieren. Angesichts der Tatsache, dass Bash eine Vielzahl nützlicher Funktionen hat, würde ich davon ausgehen, dass diese implementiert wurde, aber ich frage mich, wie.


866
2017-08-20 12:11


Ursprung


Antworten:


Bash Alias ​​akzeptiert Parameter nicht direkt. Sie müssen eine Funktion erstellen und das Alias ​​erstellen.

alias akzeptiert keine Parameter, aber eine Funktion kann wie ein Alias ​​aufgerufen werden. Beispielsweise:

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


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

By the way, Bash Funktionen in Ihrem definiert .bashrc und andere Dateien sind als Befehle in Ihrer Shell verfügbar. So können Sie zum Beispiel die frühere Funktion so aufrufen

$ myfunction original.conf my.conf

1500
2017-08-20 12:15



Wenn Sie die obige Antwort verfeinern, können Sie eine 1-Zeilen-Syntax wie für Aliase erhalten, was für Ad-hoc-Definitionen in einer Shell- oder .bashrc-Datei bequemer ist:

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

bash$ myfunction original.conf my.conf

Vergessen Sie nicht das Semikolon vor der schließenden rechten Klammer. Ähnlich 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; }

139
2018-05-14 15:46



Die Frage wird einfach falsch gestellt. Sie machen keinen Alias, der Parameter akzeptiert, weil alias fügt nur einen zweiten Namen für etwas hinzu, das bereits existiert. Die Funktionalität, die das OP wünscht, ist die function Befehl zum Erstellen einer neuen Funktion. Sie müssen die Funktion nicht umbenennen, 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 einfach mit $ @ füllen


77
2018-01-08 06:35



TL; DR: Tun Sie das 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 nicht über die Verarbeitung von Shell-Argumenten wissen müssen. Wissen ist gefährlich. Erhalte einfach das gewünschte Ergebnis, bevor die dunkle Seite für immer dein Schicksal kontrolliert.

Klärung

bash Aliase machen akzeptieren Argumente, aber nur bei der Ende:

$ alias speak=echo
$ speak hello world
hello world

Argumente ins Spiel bringen Mitte von Befehl über alias ist zwar möglich, aber es wird hässlich.

Versuchen Sie das nicht zu Hause, Kinder!

Wenn Sie gerne Einschränkungen umgehen und tun, was andere sagen, ist unmöglich, hier ist das Rezept. Gib mir nicht die Schuld, wenn dein Haar zerfetzt wird und dein Gesicht in Ruß verkrustet ist - Wissenschaftler-Stil.

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

Lösung 1

Wenn Sie wirklich dagegen sind, eine Funktion per se zu verwenden, 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 $1 wenn du nur das erste Argument willst.

Erklärung 1

Dies erstellt eine temporäre Funktion f, die die Argumente übergeben wird (beachten Sie, dass f wird ganz am Ende genannt). Das unset -f Entfernt die Funktionsdefinition, während der Alias ​​ausgeführt wird.

Lösung 2

Sie können auch eine Untershell verwenden:

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

Erläuterung 2

Der Alias ​​erstellt einen Befehl wie:

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

Bemerkungen:

  • Der Platzhalter _ ist erforderlich, aber es könnte alles sein. Es wird eingestellt shist es $0und ist erforderlich, damit das erste der vom Benutzer angegebenen Argumente nicht konsumiert 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 arbeitet:

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

    Hier die Werte der interaktiven Shell $0 und $@ werden in den doppelten zitiert ersetzt Vor es wird weitergegeben 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 werden und wortwörtlich an sie übergeben werden sh -c.

    Sie könnten doppelte Anführungszeichen und verwenden \$@, aber am besten zitieren Sie Ihre Argumente (da sie Leerzeichen enthalten können) und \"\$@\" sieht noch hässlicher aus, kann Ihnen aber helfen, einen Verschleierungswettbewerb zu gewinnen, bei dem zerfranstes Haar Voraussetzung für den Eintritt ist.


58
2018-02-26 08:40



Eine alternative Lösung ist zu verwenden Marker, ein Werkzeug, das ich vor kurzem erstellt habe, das es Ihnen ermöglicht, Befehlsvorlagen zu "bookmarken" und den Cursor einfach auf Befehls-Platzhalter zu setzen:

commandline marker

Ich habe herausgefunden, dass ich die meiste Zeit Shell-Funktionen verwende, so dass ich häufig verwendete Befehle nicht immer wieder in der Befehlszeile schreiben muss. Das Problem, Funktionen für diesen Anwendungsfall zu verwenden, besteht darin, meinem Befehlsvokabular neue Begriffe hinzuzufügen und daran zu erinnern, auf welche Funktionen Parameter im reellen Befehl verweisen. Marker Ziel ist es, diese mentale Belastung zu beseitigen.


26
2018-05-22 12:39



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

#Utility required by all below functions.
#https://stackoverflow.com/questions/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:


7
2018-01-13 03:57



NB: Wenn die Idee nicht offensichtlich ist, ist es eine schlechte Idee Aliase aber Aliase für etwas zu verwenden, wobei die erste die ‚Funktion in einem Alias‘ und das zweite ist das Sein ‚schwer zu lesen umleiten / Quelle‘. Außerdem gibt es Fehler (die ich habe gedacht wäre offensichtlich, aber nur für den Fall, dass Sie verwirrt sind: Ich meine nicht, dass sie tatsächlich benutzt werden ... überall!)

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

Ich habe das schon einmal beantwortet, und das 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 alle zusammen. In diesem Fall können Sie die enorme Fähigkeit von bash nutzen, Text umzuleiten:

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

Sie haben beide etwa die gleiche Länge oder geben ein paar Zeichen.

Das echt kicker ist der Zeitunterschied, wobei der obere die 'Funktionsmethode' und der untere die 'redirect-source' Methode ist. Um diese Theorie zu beweisen, spricht das Timing für sich selbst:

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 in zufälligen Intervallen. Es scheint, dass das Erstellen / Löschen von Funktionen länger dauert als die Umleitung. Hoffentlich hilft dies zukünftigen Besuchern dieser Frage (wollte es nicht für mich behalten).


4
2018-05-20 18:39



Um Parameter zu nehmen, sollten Sie Funktionen verwenden!

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

Sie müssen 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 "$@" ;}

Schließlich rufen Sie Ihre foo () mit der folgenden Syntax auf:

foo arg1 arg2 argN

Stellen Sie sicher, dass Sie Ihren foo () hinzufügen ~/.bash_profile oder ~/.zshrc Datei.

In Ihrem Fall wird das funktionieren

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

2
2017-07-28 09:15



Es gibt legitime technische Gründe, eine generalisierte Lösung für das Problem von bash alias zu wollen, das 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 in der Umgebung, die sich aus der Ausführung einer Funktion ergeben, beeinträchtigt wird. Insgesamt andere Fälle sollten Funktionen verwendet werden.

Was mich kürzlich dazu bewogen 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. Also habe ich einige Funktionen für diesen Zweck geschrieben. Es gibt jedoch bestimmte Variablen, die durch einen Funktionsaufruf selbst verändert werden (oder werden können). Unter ihnen sind:

FUNKTIONSNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Der grundlegende Befehl, den ich (in einer Funktion) verwendet habe, um variable Definitionen zu drucken. In der Form, die vom Set-Befehl ausgegeben wurde, 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 so ausgegeben, wie sie in der aktueller KontextB. wenn in einer interaktiven Shell-Eingabeaufforderung (oder in keiner Funktionsaufrufe) 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 spezifischen Befehl zum Drucken von Variablen-Definitionen., Und der nur ein Argument benötigt, habe ich Folgendes getan:

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

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

> asv FUNCNAME
> echo $?
1

Dennoch fühlte ich mich gezwungen, eine Lösung zu finden, die für eine beliebige Anzahl von Argumenten funktioniert.

Eine allgemeine Lösung zum Übergeben von willkürlichen Argumenten an einen Bash Aliased-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 verwendet werden, um Positionsparameter (Argumente) zu Befehlen zu handhaben, beim Zusammensetzen des eingefangenen 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 [@]}".

Etc.


2
2017-10-18 17:35



Wenn Sie nach einer allgemeinen Möglichkeit suchen, alle Parameter auf eine Funktion anzuwenden, nicht nur auf einen oder zwei oder einen anderen fest codierten Betrag, 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 ab dem Zeitpunkt der Ausführung runjar zum Alias.

Zum Beispiel, wenn ich es getan habe runjar hi there es würde am Ende tatsächlich laufen java -jar myjar.jar hi there. Wenn ich es tat runjar one two three es würde laufen java -jar myjar.jar one two three.

Ich mag das $@ - basierte Lösung, weil es mit einer beliebigen Anzahl von Parametern arbeitet.


1
2017-08-29 20:54



Funktionen sind in der Tat fast immer die Antwort, wie bereits ausführlich von diesem Zitat aus der Manpage bestätigt und bestätigt: "Für fast jeden Zweck werden Aliase durch Shell-Funktionen ersetzt."

Der Vollständigkeit halber und weil dies nützlich sein kann (marginal leichtere Syntax), könnte angemerkt werden, dass, wenn die Parameter dem Alias ​​folgen, sie immer noch verwendet werden können (obwohl dies die Anforderung des OP nicht erfüllen würde). Dies ist wahrscheinlich am einfachsten anhand eines Beispiels zu demonstrieren:

alias ssh_disc='ssh -O stop'

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

Dies kann nützlich sein für Befehle, die komplexe Argumente benötigen (mein Gedächtnis ist nicht mehr das, was es benutzt ...)


0
2018-03-19 10:19