Question Faire un alias Bash qui prend un paramètre?


J'avais l'habitude d'utiliser CShell (), ce qui vous permet de créer un alias prenant un paramètre. La notation était quelque chose comme

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

Dans Bash, cela ne semble pas fonctionner. Étant donné que Bash a une multitude de fonctionnalités utiles, je suppose que celui-ci a été implémenté mais je me demande comment.


866
2017-08-20 12:11


origine


Réponses:


L'alias Bash n'accepte pas directement les paramètres. Vous devrez créer une fonction et un alias.

alias n'accepte pas les paramètres mais une fonction peut être appelée comme un alias. Par exemple:

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


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

Par ailleurs, les fonctions Bash définies dans votre .bashrc et d'autres fichiers sont disponibles en tant que commandes dans votre shell. Ainsi, par exemple, vous pouvez appeler la fonction précédente comme celle-ci

$ myfunction original.conf my.conf

1500
2017-08-20 12:15



En affinant la réponse ci-dessus, vous pouvez obtenir une syntaxe à une ligne comme vous pouvez pour les alias, ce qui est plus pratique pour les définitions ad-hoc dans un shell ou des fichiers .bashrc:

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

bash$ myfunction original.conf my.conf

Ne pas oublier le point-virgule avant le crochet de droite. De même, pour la question réelle:

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

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

Ou:

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

139
2018-05-14 15:46



La question est simplement mal posée. Vous ne faites pas un alias qui prend des paramètres parce que alias ajoute juste un deuxième nom pour quelque chose qui existe déjà. La fonctionnalité que l'OP veut est la function commande pour créer une nouvelle fonction. Vous n'avez pas besoin d'alias la fonction car la fonction a déjà un nom.

Je pense que vous voulez quelque chose comme ça:

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

C'est tout! Vous pouvez utiliser les paramètres $ 1, $ 2, $ 3, etc, ou simplement les bourrer de $ @


77
2018-01-08 06:35



TL; DR: Faites ceci à la place

C'est beaucoup plus facile et plus lisible d'utiliser une fonction qu'un alias pour mettre des arguments au milieu d'une commande.

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

Si vous continuez, vous apprendrez des choses que vous n'avez pas besoin de savoir sur le traitement des arguments shell. La connaissance est dangereuse. Obtenez juste le résultat que vous voulez, avant que le côté obscur contrôle pour toujours votre destin.

Clarification

bash alias faire accepter les arguments, mais seulement au fin:

$ alias speak=echo
$ speak hello world
hello world

Mettre des arguments dans le milieu de la commande via alias est en effet possible mais ça devient moche.

N'essaye pas ça à la maison, kiddies!

Si vous aimez contourner les limitations et faire ce que les autres disent est impossible, voici la recette. Ne me blâmez pas si vos cheveux sont ébouriffés et que votre visage est couvert de suie-scientifique.

La solution de contournement consiste à transmettre les arguments alias accepte seulement à la fin d'un wrapper qui va les insérer au milieu et ensuite exécuter votre commande.

Solution 1

Si vous êtes vraiment contre l'utilisation d'une fonction en soi, vous pouvez utiliser:

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

Vous pouvez remplacer $@ avec $1 si vous voulez seulement le premier argument.

Explication 1

Cela crée une fonction temporaire f, qui est passé les arguments (notez que f est appelé à la toute fin). le unset -f supprime la définition de la fonction lorsque l'alias est exécuté afin de ne pas traîner par la suite.

Solution 2

Vous pouvez également utiliser un sous-shell:

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

Explication 2

L'alias construit une commande comme:

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

Commentaires:

  • L'espace réservé _ est nécessaire, mais cela pourrait être n'importe quoi. Il se met à shde $0et est requis pour que le premier des arguments donnés par l'utilisateur ne soit pas consommé. Manifestation:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
    
  • Les guillemets simples à l'intérieur des guillemets simples sont obligatoires. Voici un exemple qui ne fonctionne pas avec des guillemets:

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

    Voici les valeurs du shell interactif $0 et $@ sont remplacés dans le double cité avant il est passé à sh. Voici la preuve:

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

    Les guillemets simples assurent que ces variables ne sont pas interprétées par un shell interactif et sont transmises littéralement à sh -c.

    Vous pouvez utiliser des guillemets et \$@, mais la meilleure pratique consiste à citer vos arguments (car ils peuvent contenir des espaces), et \"\$@\" semble encore plus laid, mais peut vous aider à gagner un concours d'obfuscation où les cheveux ébouriffés sont une condition préalable à l'entrée.


58
2018-02-26 08:40



Une solution alternative est d'utiliser marqueur, un outil que j'ai créé récemment et qui vous permet de "mettre en signet" des modèles de commande et de placer facilement le curseur sur les emplacements de commande:

commandline marker

J'ai trouvé que la plupart du temps, j'utilise des fonctions shell, donc je n'ai pas besoin d'écrire des commandes fréquemment utilisées encore et encore dans la ligne de commande. Le problème de l'utilisation des fonctions pour ce cas d'utilisation, est d'ajouter de nouveaux termes à mon vocabulaire de commande et de devoir se souvenir des fonctions auxquelles les paramètres se réfèrent dans la commande réelle. L'objectif du marqueur est d'éliminer ce fardeau mental.


26
2018-05-22 12:39



Voici trois exemples de fonctions que j'ai dans mon ~/.bashrc, qui sont essentiellement alias qui acceptent un paramètre:

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

Les références:


7
2018-01-13 03:57



NB: Dans le cas où l'idée n'est pas évidente, c'est une mauvaise idée d'utiliser des alias pour autre chose que des alias, le premier étant la fonction dans un alias et le second étant la redirection / source difficile à lire. En outre, il y a des défauts (que je pensée serait évident, mais juste au cas où vous êtes confus: je ne veux pas qu'ils soient effectivement utilisés ... n'importe où!)

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

J'ai déjà répondu à cela, et ça a toujours été comme ça dans le passé:

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

ce qui est bien et bon, à moins que vous évitiez l'utilisation des fonctions tous ensemble. Dans ce cas, vous pouvez profiter de la vaste capacité de bash à rediriger le texte:

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

Ils sont tous deux à peu près de la même longueur donner ou prendre quelques caractères.

le réal kicker est la différence de temps, la partie supérieure étant la 'méthode de la fonction' et la partie inférieure étant la méthode 'source-redirect'. Pour prouver cette théorie, le timing parle de lui-même:

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

C'est la partie inférieure d'environ 200 résultats, faits à des intervalles aléatoires. Il semble que la création / destruction de fonction prenne plus de temps que la redirection. J'espère que cela aidera les futurs visiteurs à cette question (je ne voulais pas la garder pour moi).


4
2018-05-20 18:39



Pour prendre des paramètres, vous devez utiliser des fonctions!

Cependant $ @ est interprété lors de la création de l'alias au lieu de lors de l'exécution de l'alias et l'échappement du $ ne fonctionne pas non plus. Comment puis-je résoudre ce problème?

Vous devez utiliser la fonction shell au lieu d'un alias pour vous débarrasser de ce problème. Vous pouvez définir foo comme suit:

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

OU

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

Enfin, appelez votre foo () en utilisant la syntaxe suivante:

foo arg1 arg2 argN

Assurez-vous d'ajouter votre foo () à ~/.bash_profile ou ~/.zshrc fichier.

Dans votre cas, cela fonctionnera

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

2
2017-07-28 09:15