Faire un alias Bash qui prend un paramètre?

j'utilisais cshell ( ), qui vous permet de créer un alias qui prend un paramètre. La notation était quelque chose comme

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

En Bash, cela ne semble pas fonctionner. Étant donné que Bash a une multitude de fonctionnalités utiles, je suppose que celle-ci a été mise en œuvre, mais je me demande comment.

907
demandé sur codeforester 2011-08-20 16:11:41

12 réponses

Bash alias n'accepte pas directement les paramètres. Vous aurez à créer une fonction et 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  such as
    mv "" ".bak"
    cp "" ""
}


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

soit dit en passant, les fonctions de Bash définies dans votre .bashrc et d'autres fichiers sont disponibles sous forme de commandes dans votre shell. Ainsi, par exemple, vous pouvez appeler la fonction précédente comme ceci

$ myfunction original.conf my.conf
1557
répondu arunkumar 2018-06-12 16:02:49

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

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

bash$ myfunction original.conf my.conf

N'oubliez pas le point-virgule avant le crochet droit de fermeture. De même, pour la question actuelle:

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

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

ou:

bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }
145
répondu Mike Gleason 2014-05-14 16:10:13

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

je pense que vous voulez quelque chose comme ceci :

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

C'est ça! Vous pouvez utiliser les paramètres 1$ ,2$, 3 $, etc, ou juste des trucs avec $@

84
répondu Evan Langlois 2017-08-10 05:11:12

TL;DR: le Faire à la place

Son beaucoup plus facile et plus lisible d'utiliser une fonction qu'un alias de mettre des arguments au moyen d'une commande.

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

si vous lisez la suite, vous apprendrez des choses que vous n'avez pas besoin de savoir sur le traitement des arguments shell. La connaissance est dangereuse. Juste obtenir le résultat que vous voulez, avant que le côté obscur pour toujours contrôle votre destin.

Clarification

bash alias faire accepter des arguments, mais seulement à la fin :

$ alias speak=echo
$ speak hello world
hello world

mettre des arguments dans le moyen de commande via alias est en effet possible, mais il devient laid.

n'essayez pas ça à la maison, les enfants!

si vous aimez contourner les limites et faire ce que les autres disent est impossible, voici la recette. Il suffit de ne pas l'en blâmer moi, si tes cheveux sont égratignés et que ton visage finit couvert de suie.

la solution est de passer les arguments que alias n'accepte qu'à la fin à un wrapper qui les insérera au milieu et exécutera ensuite 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 $@ par si vous voulez seulement le premier argument.

Explication 1

f cela crée une fonction temporaire f , qui est passée les arguments (notez que f est appelé à la toute fin). Le unset -f supprime la définition de la fonction puisque l'alias est exécuté pour qu'il ne traîne pas par la suite.

Solution 2

vous pouvez également utiliser une sous-couche:

$ 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 il pourrait être n'importe quoi. Il est défini à sh 's " 1519180920" , et est requis pour que le premier des arguments donnés par l'utilisateur ne soit pas consommé. Démonstration:

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

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

    ici les valeurs des shell interactifs "1519180920" et $@ sont remplacées par le double coté avant il est passé à sh . En voici la preuve:

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

    les guillemets simples assurent que ces variables sont non interprété par interactive shell, et sont passés littéralement à sh -c .

    vous pouvez utiliser des doubles-citations et $@ , mais la meilleure pratique est de 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 éraflés est une condition préalable pour l'entrée.

61
répondu Tom Hale 2017-05-23 03:02:51

une solution alternative est d'utiliser marqueur , un outil que j'ai créé récemment qui vous permet de "marque-page" gabarits de commande et facilement placer le curseur à la commande des titulaires de place:

commandline marker

j'ai trouvé que la plupart du temps, j'utilise des fonctions shell donc je n'ai pas à écrire des commandes fréquemment utilisées encore et encore dans la ligne de commande. La question de l'utilisation de fonctions pour ce cas d'utilisation, est l'ajout de nouveaux définit mon vocabulaire de commande et doit se souvenir des paramètres de fonctions auxquels se réfère la commande real-command. Marqueur objectif est d'éliminer la charge mentale.

27
répondu Amine Hajyoussef 2015-05-22 13:24:24

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.
#/q/how-to-trim-whitespace-from-a-bash-variable-53952/"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 "" | 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 ""
}

.

:<<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 "" | 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
répondu aliteralmind 2017-05-23 11:55:03

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 le 'redirect/source difficile à lire'. En outre, il ya des défauts (que je pensé serait évident, mais juste au cas où vous êtes confus: Je ne veux pas dire qu'ils sont effectivement utilisés... n'importe où!)

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

j'ai déjà répondu à cette question, et cela a toujours été ainsi dans le passé:

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

ce qui est bien et bien, à moins que vous évitiez l'utilisation de toutes les fonctions ensemble. dans ce cas, vous pouvez profiter de la vaste capacité de bash de rediriger du texte:

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

ils sont les deux sur la même longueur donner ou prendre quelques caractères.

le réel kicker est le décalage horaire, le haut étant la 'méthode de fonction' et le bas étant la méthode 'redirect-source'. 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, effectuée à des intervalles aléatoires. Il semble que la création/destruction de fonction prend plus de temps que la redirection. J'espère que ce les futurs visiteurs de cette question (ne veux pas le garder pour moi).

4
répondu osirisgothra 2015-05-21 13:08:48

pour la prise de paramètres, vous devez utiliser des fonctions!

cependant $@ obtenir interprété lors de la création de l'alias au lieu de pendant l'exécution de l'alias et échapper à la $ 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 se 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() utilisant la syntaxe suivante:

foo arg1 arg2 argN

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

Dans votre cas, cela fonctionne

function trash() { mv $@ ~/.Trash; }
2
répondu Ahmad Awais 2016-07-28 09:15:37

il y a des raisons techniques légitimes pour vouloir une solution généralisée au problème de bash alias n'ayant pas de mécanisme pour prendre un repositionnement des arguments arbitraires. Une raison est si la commande que vous souhaitez exécuter serait affectée négativement par les changements à l'environnement qui résultent de l'exécution d'une fonction. Dans tous les cas autres , des fonctions doivent être utilisées.

ce qui m'a récemment contraint à tenter une solution à ce problème, c'est que je voulait créer quelques commandes abrégées pour imprimer les définitions de variables et de fonctions. Donc j'ai écrit quelques fonctions dans ce but. Cependant, il y a certaines variables qui sont (ou peuvent être) modifiées par un appel de fonction lui-même. Parmi eux:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

la commande de base que j'utilisais (dans une fonction) pour imprimer des defns variables. dans la sortie de la forme par la commande set était:

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

par exemple:

> V=voodoo
sv V
V=voodoo

problème: cela n'imprimera pas les définitions des variables mentionnées ci-dessus car elles sont dans le contexte actuel , par exemple, si dans un invite de shell interactif (ou pas dans les appels de fonction), FUNCNAME n'est pas défini. Mais ma fonction me dit la mauvaise information:

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

une solution que j'ai trouvée a été mentionnée par d'autres dans d'autres Billets sur ce sujet. Pour cette commande spécifique pour imprimer les variables defns., et qui n'exige qu'un seul argument, j'ai fait ceci:

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

qui donne la sortie correcte (none), et l'état du résultat (false):

> asv FUNCNAME
> echo $?
1

cependant, je me suis senti obligé de trouver une solution qui fonctionne pour un nombre arbitraire d'arguments.

Une Solution Générale Pour Passer Des Arguments Arbitraires À Un Bash Alias De Commande:

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

par exemple:

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

une bonne chose à propos de cette solution est que toutes les astuces spéciales utilisées pour gérer les paramètres de position (arguments) des commandes fonctionneront lors de la composition de la commande piégée. La seule différence est que la syntaxe du tableau doit être utilisée.

par exemple,

si vous voulez "$@", utilisez "${CMD_ARGV[@]}".

si vous voulez "$#", utilisez "${#CMD_ARGV[@]}".

etc.

2
répondu crobc1 2017-10-18 17:42:09

si vous cherchez une façon générique d'appliquer toutes les params à une fonction, pas seulement une ou deux ou une autre quantité codée, vous pouvez le faire de cette façon:

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

donc dans l'exemple ci-dessus, je passe tous les paramètres à partir du moment où j'exécute runjar à l'alias.

par exemple, si je faisais runjar hi there , cela finirait en fait par java -jar myjar.jar hi there . Si je faisais runjar one two three , je dirais java -jar myjar.jar one two three .

j'aime ça $@ - solution basée parce qu'elle fonctionne avec n'importe quel nombre de params.

1
répondu Micah 2015-08-29 20:54:46

fonctions sont en effet presque toujours la réponse comme déjà amplement contribué et confirmé par cette citation de la page de manuel: "pour presque tous les buts, les alias sont remplacés par des fonctions shell."

par souci d'exhaustivité et parce que cela peut être utile (syntaxe légèrement plus légère), on peut noter que lorsque le(S) paramètre (s) suit (NT) l'alias, ils peuvent toujours être utilisés (bien que cela ne répondrait pas à l'exigence de L'OP). C'est probablement plus facile à démontrer avec un exemple:

alias ssh_disc='ssh -O stop'

me permet de taper smth comme ssh_disc myhost , qui est élargi comme prévu comme: ssh -O stop myhost

cela peut être utile pour les commandes qui prennent des arguments complexes (ma mémoire n'est plus ce qu'elle est...)

0
répondu sxc731 2016-03-19 10:19:18

vous n'avez cependant pas besoin de fonctions pour créer des alias dans le fichier .bashrc . Par exemple

# create an alias that takes port-number by the user
alias serve="python -m SimpleHTTPServer "

après avoir fait le changement dans le .bashrc fichier, assurez-vous d'entrer la commande suivante.

~$ source .bashrc

Vous devriez être capable de l'utiliser comme si

~$ serve 8998
-3
répondu kaizer1v 2017-11-10 03:44:43