Faire un alias Bash qui prend un paramètre?

1273

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

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

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

Bonjour
la source
2
Assurez-vous d'utiliser des guillemets autour des arguments"$1"
Christophe Roussy
Cette question est hors sujet pour SO. Il a été répondu à UNIX.SE , et la réponse est que vous n'avez pas besoin même de la peine: « Par exemple, si vous deviez alias lsà ls -la, puis en tapant ls foo barserait vraiment exécuter ls -la foo barsur la ligne de commande. »
Dan Dascalescu
7
cela n'aiderait pas à interpoler une variable au milieu d'une chaîne
Franz Sittampalam
1
Voici l'alias de test lil que j'ai utilisé pour découvrir cette erreur ... alias test_args="echo PREFIX --$1-- SUFFIX", qui lorsqu'elle est appelée avec test_args ABCDdonne la sortie de console suivantePREFIX ---- SUFFIX ABCD
jxramos

Réponses:

2126

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

aliasn'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`

Soit dit en passant, les fonctions Bash définies dans vos .bashrcfichiers et dans d'autres sont disponibles sous forme de commandes dans votre shell. Ainsi, par exemple, vous pouvez appeler la fonction précédente comme celle-ci

$ myfunction original.conf my.conf
arunkumar
la source
48
Dois-je mettre $1entre guillemets?
Jürgen Paul
263
Vous n'avez même pas besoin de déclarer l'alias. Il suffit de définir la fonction.
dinigo
207
Si vous changez un alias en fonction, sourcevotre .bashrc ajoutera la fonction mais ne désaliasera pas l'ancien alias. Étant donné que les alias ont un précédent plus élevé que les fonctions, il essaiera d'utiliser l'alias. Vous devez soit fermer et rouvrir votre shell, soit appeler unalias <name>. Je sauverai peut-être quelqu'un les 5 minutes que je viens de perdre.
Marty Neal
56
@MartinNeal: Une astuce pour gagner du temps que j'ai apprise chez Sun est de faire juste un exec bash: il va démarrer un nouveau shell, vous donnant une lecture claire de vos configurations, comme si vous fermiez et rouvriez, mais en gardant aussi les paramètres des variables d'environnement de cette session . En outre, l'exécution bashsans l'exec peut être utile lorsque vous souhaitez gérer pense comme une pile.
Macneil Shonle
21
@mich - oui, mettez toujours les variables bash entre guillemets. par exemple mv "$1" "$1.bak". sans guillemets, si $ 1 était "hello world", vous l'exécuteriez à la mv hello world hello world.bakplace de mv "hello world" "hello world.bak".
orion elenzil
208

En 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 des fichiers .bashrc:

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

bash$ myfunction original.conf my.conf

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

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

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

Ou:

bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }
Mike Gleason
la source
3
Je préfère cette réponse, car elle montre l'itération à travers le tableau d'arguments qui pourraient entrer. $ 1 et $ 2 ne sont que des cas spéciaux, ce qui est également illustré dans cette réponse.
philo vivero
16
Passez mv "$1" "$1.bak"; cp "$2" "$1" à mv "$1" "$1.bak" && cp "$2" "$1"pour ne pas perdre vos données mven cas de problème (par exemple, système de fichiers plein).
Henk Langeveld
3
"N'oubliez pas le point-virgule avant la fermeture du crochet droit." Plusieurs fois cela! Merci :)
Kaushal Modi
Et les espaces après le premier support et avant le dernier support sont également requis.
Bryan Chapel
1
@HenkLangeveld Bien que votre remarque soit parfaitement correcte, elle montre que vous êtes là depuis un certain temps - je ne saurais pas quand j'ai rencontré pour la dernière fois une erreur "il ne reste plus d'espace sur l'appareil" ;-). (Je l'utilise régulièrement mais quand je ne trouve plus d'espace sur le comptoir de la cuisine!) Cela ne semble pas arriver très souvent de nos jours.
Peter - Rétablir Monica
124

La question est simplement mal posée. Vous ne créez pas d'alias qui accepte des paramètres car il aliassuffit d'ajouter un deuxième nom pour quelque chose qui existe déjà. La fonctionnalité souhaitée par l'OP est la functioncommande 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 ça! Vous pouvez utiliser les paramètres $ 1, $ 2, $ 3, etc., ou tout simplement les remplir avec $ @

Evan Langlois
la source
7
Cette réponse dit tout. Si j'avais lu au bas de cette page, j'aurais gagné du temps.
joe
-1 Un alias et une fonction ne sont pas équivalents ...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
Vous devriez vraiment citer $@pour prendre en charge les noms de fichiers avec des espaces, etc.
Tom Hale
C'était censé être une explication générale que vous n'avez pas de paramètres d'alias, vous utilisez plutôt une fonction. La fonction donnée n'était qu'un exemple pour contrer l'exemple d'origine. Je ne pense pas que la personne recherchait une fonction poubelle à usage général. Cependant, dans l'intérêt de présenter un meilleur code, j'ai mis à jour la réponse.
Evan Langlois
1
@FuzzyLogic - J'ai passé quelques minutes à essayer de décompresser le code dans votre commentaire. C'est beaucoup d'efforts (intéressants) à faire pour emballer du code dans un commentaire où vous ne pouvez pas le formater correctement. Je n'ai toujours pas compris exactement ce qu'il fait ou, plus important encore, pourquoi il soutient votre affirmation (correcte).
Joe
110

TL; DR: faites ceci à la place

Il est beaucoup plus facile et plus lisible d'utiliser une fonction qu'un alias pour placer 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 à lire, vous apprendrez des choses que vous n'avez pas besoin de savoir sur le traitement des arguments du shell. La connaissance est dangereuse. Obtenez juste le résultat que vous voulez, avant que le côté obscur ne contrôle à jamais votre destin.

Clarification

bashalias n'acceptent des arguments, mais seulement à la fin :

$ alias speak=echo
$ speak hello world
hello world

Mettre des arguments au milieu de la commande via aliasest en effet possible mais cela devient moche.

N'essayez pas cela à la maison, les enfants!

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 se frottent et que votre visage finit par être couvert de suie.

La solution de contournement consiste à passer les arguments qui aliasn'acceptent qu'à la fin à un wrapper qui les insérera au milieu, puis exécutera 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 $1si vous ne voulez que le premier argument.

Explication 1

Cela crée une fonction temporaire f, à laquelle sont passés les arguments (remarque qui fest appelée à la toute fin). Le unset -fsupprime la définition de la fonction à mesure que l'alias est exécuté afin qu'il ne reste pas après.

Solution 2

Vous pouvez également utiliser un sous-shell:

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

Explication 2

L'alias crée une commande comme:

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

Commentaires:

  • L'espace réservé _est obligatoire, mais il peut s'agir de n'importe quoi. Il est défini sur sh's' $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 de non fonctionnement avec des guillemets doubles:

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

    Ici, les valeurs de l'interpréteur de commandes interactif $0et $@sont remplacées par le double entre guillemets avant d' être passées à sh. Voici la preuve:

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

    Les guillemets simples garantissent 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 doubles 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'obscurcissement où les cheveux ébouriffés sont une condition préalable à la participation.

Tom Hale
la source
2
pour la solution 1, assurez-vous d'utiliser des guillemets simples et évitez \ "dans le $ @. Une technique très utile si vous en avez besoin. ty.
sgtz
La solution 1 a fonctionné pour moi envelopper rdesktop-vrdp avec un argument pour chaque serveur que je veux.
Hsehdar
Accepter les arguments à la fin est exactement ce dont j'avais besoin pour remplacer "git checkout {branchname}" par un simple "gc {branchname}". Dans .bash_profile, je devais simplement ajouteralias gc='git checkout'
AbstractVoid
@sgtz pourquoi voudriez-vous supprimer les guillemets $@? Ils sont nécessaires si vous avez, par exemple, des fichiers contenant des espaces.
Tom Hale
@TomHale C'est un peu linguistique, mais la solution 1 n'est pas vraiment utile si quelqu'un est vraiment contre l'utilisation d'une fonction (quelle qu'en soit la raison) car vous vous reconnaissez directement après que vous ne faites que déplacer la définition d'une fonction sur le temps d'exécution de l'alias. deuxièmement, «les alias bash acceptent les arguments, mais seulement à la fin» est plus sémantique: les alias sont par définition des substitutions de mots par des chaînes. ils n'ont pas besoin d'accepter les arguments, les commandes qui sont exécutées via la substitution le peuvent cependant. alias est un remplacement de personnage, rien de plus, rien de moins. non?
BUFU
39

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

marqueur de ligne de commande

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

Amine Hajyoussef
la source
14

Tout ce que vous avez à faire est de créer une fonction à l'intérieur d'un alias:

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

Vous devez mettre des guillemets doubles autour de "$ 1" car les guillemets simples ne fonctionneront pas.

Ken Tran
la source
5
C'est intelligent, mais à part le fait que la question précise de créer un alias, y a-t-il une raison pour ne pas simplement faire la fonction avec le même nom que l'alias au départ?
xaxxon
1
@xaxxon Pas vraiment, mais c'est la façon la plus simple que je connaisse d'utiliser un alias, pas une fonction.
Ken Tran
1
Cela ne fonctionne pas. Sur Ubuntu 18, je reçois une erreur bash: syntax error near unexpected token '{mkdir'.
Shital Shah
il manque probablement une fin ;à l'intérieur de la fonction _mkcd.
Jetchisel
Laissez de l'espace avant et après le {et}
hesham_EE
10

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

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

Références:

aliteralmind
la source
Hein? C'est une fonction, pas un alias. Et l'une de vos références est cette question même.
tripleee
2
Non, cela fonctionne exactement comme une fonction. Comme plusieurs des réponses ici l'expliquent, vous ne pouvez pas créer un alias qui accepte un paramètre. Ce que vous pouvez faire, c'est écrire une fonction, c'est ce que vous avez fait.
tripleee
1
@tripleee De mon point de vue de débutant bash, avant de lire votre commentaire, je pensais que c'était un alias (une autre façon d'en créer un). Il fonctionne exactement comme un, pour autant que je sache. C'est essentiellement un alias qui accepte un paramètre, même si je ne suis pas sur la terminologie. Je ne vois pas le problème. J'ai clarifié le lien vers l'autre réponse dans ce problème. Cela m'a aidé à créer cela.
aliteralmind
1
Peut-être que cela ne répond pas spécifiquement à la question "d'un alias bash qui accepte un paramètre", parce que je comprends maintenant que ce n'est pas possible, mais il y répond certainement efficacement . Qu'est-ce que j'oublie ici?
aliteralmind
2
De très bons exemples ici, et du code bien commenté. Une grande aide pour les personnes qui viennent sur cette page.
chim
9

L'alias Bash accepte absolument les paramètres. Je viens d'ajouter un alias pour créer une nouvelle application React qui accepte le nom de l'application comme paramètre. Voici mon processus:

Ouvrez le bash_profile pour le modifier dans nano

nano /.bash_profile

Ajoutez vos alias, un par ligne:

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

note: le "$ @" accepte les paramètres passés comme "creact my-new-app"

Enregistrer et quitter l'éditeur nano

ctrl + o pour écrire (appuyez sur Entrée); ctrl + x pour quitter

Dites au terminal d'utiliser les nouveaux alias dans .bash_profile

source /.bash_profile

C'est ça! Vous pouvez maintenant utiliser vos nouveaux alias

Billeh
la source
6

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 ''. De plus, il y a des défauts (que je pensais être évidents, mais juste au cas où vous seriez confus: je ne veux pas qu'ils soient réellement utilisés ... n'importe où!)

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

J'ai déjà répondu à cela, et cela 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, sauf si vous évitez d'utiliser toutes les fonctions ensemble. dans ce cas, vous pouvez profiter de la grande capacité de bash à rediriger le texte:

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

Ils sont tous les deux de la même longueur, donnent ou prennent quelques caractères.

Le vrai kicker est la différence de temps, le haut étant la «méthode de fonction» et le bas étant la méthode de «redirection-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

Il s'agit de la partie inférieure d'environ 200 résultats, effectués à des intervalles aléatoires. Il semble que la création / destruction de fonctions 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).

osirisgothra
la source
2
Avoir un alias qui définit une fonction, puis exécuter cette fonction est tout simplement idiot. Écrivez simplement une fonction. Dans presque tous les cas, les alias sont remplacés par des fonctions shell.
geirha
1
Le second (l'alias de la barre) a plusieurs effets secondaires. Premièrement, la commande ne peut pas utiliser stdin. Deuxièmement, si aucun argument n'est fourni après l'alias, tous les arguments que le shell se trouve sont passés à la place. L'utilisation d'une fonction évite tous ces effets secondaires. (Utilisation également inutile de chat).
geirha
2
hé je n'ai jamais dit que c'était une bonne idée de faire tout ça, j'ai juste dit qu'il y avait aussi d'autres façons de procéder - l'idée principale ici est que vous ne devriez pas utiliser les fonctions dans les alias car elles sont plus lentes que compliquées rediriger, je pensais que cela aurait été évident mais je suppose que je dois l'épeler pour tout le monde (que je reçois également crié pour que le message soit trop gonflé si je le faisais en premier lieu)
osirisgothra
1
Étant donné que les timings de la barre sont tous des 0, je soupçonne que le shell ne chronomètre pas correctement. Notez que le message d'heure est imprimé avant l'exécution de la commande? Ergo, il ne chronomètre rien et exécute ensuite la mesure, donc vous ne mesurez pas la mesure du tout. Faites quelque chose de plus complexe, ou une grosse boucle dans la barre afin que vous puissiez rendre plus évident que vous ne chronométrez rien
Evan Langlois
1
J'ai maintenant essayé ceci (bien que je devais remplacer le __foo () final par __foo). time for i in {1..1000}; do foo FOOVALUE; done→ 0m0.028s. Mais time for i in {1..1000}; do bar FOOVALUE; done→ 0m2.739s. Bar est deux ordres de grandeur plus lent que foo. Le simple fait d'utiliser une fonction simple au lieu d'un alias réduit le temps d'exécution de 30% supplémentaires : function boo() { echo "arg1 for boo=$1" ; }time for i in {1..1000}; do boo FOOVALUE; done→ 0m0.019s.
Arne Babenhauserheide
6

Si vous cherchez un moyen générique d'appliquer tous les paramètres à une fonction, pas seulement un ou deux ou une autre quantité codée en dur, 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ù je cours runjarvers l'alias.

Par exemple, si je le faisais, runjar hi therecela finirait par fonctionner java -jar myjar.jar hi there. Si je le faisais, runjar one two threeça irait java -jar myjar.jar one two three.

J'aime cette $@solution basée sur le fait qu'elle fonctionne avec n'importe quel nombre de paramètres.

Michée
la source
4
pourquoi ne pas simplement nommer la fonction runjarau lieu d'en faire un alias d'une fonction? Semble inutilement compliqué!
Evan Langlois
Les fonctions @EvanLanglois sont automatiquement alias-ed (ou ayant les propriétés des choses transmises alias) dans les fichiers bash? si oui, alors c'est juste que je ne l'ai pas su
Micah
Je ne comprends pas ce que tu veux dire. Un alias est un autre nom, que ce soit une personne ou une fonction. Donc, vous avez créé une fonction, puis vous avez créé un deuxième nom pour la fonction. L'alias n'a rien de spécial, c'est juste un deuxième nom et ce n'est pas obligatoire. Ce que vous tapez sur la ligne de commande peut être des fonctions internes ou externes, donc "fonction" crée une nouvelle commande, pas un alias.
Evan Langlois
4
C'est inutile. C'est la même chose que alias runjar='java -jar myjar.jar'. Les alias acceptent les arguments, mais uniquement à la fin.
Tom Hale
6

Respectueusement à tous ceux qui disent que vous ne pouvez pas insérer un paramètre au milieu d'un alias, je viens de le tester et j'ai constaté que cela fonctionnait.

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

lorsque j'ai ensuite exécuté ma commande foobar, cela a fonctionné exactement comme si j'avais tapé la commande à la main.

Nathaniel
la source
Absolument, l'alias peut obtenir des paramètres, je suis âgé en utilisant celui-ci, par exemple: alias commit = "git commit -m $ 1"
agapitocandemor
Ne fonctionne pas pour moi: me alias myalias="echo 1 "$1" 3"; myalias 2donne:1 3 2
dirdi
4

Il existe des raisons techniques légitimes de vouloir une solution généralisée au problème de l'alias bash n'ayant pas de mécanisme pour prendre un repositionnement des arguments arbitraires. L'une des raisons est que la commande que vous souhaitez exécuter serait affectée par les modifications de l'environnement résultant de l'exécution d'une fonction. Dans tous les autres cas, les fonctions doivent être utilisées.

Ce qui m'a récemment poussé à essayer une solution, c'est que je voulais créer des commandes abrégées pour imprimer les définitions des variables et des fonctions. J'ai donc écrit quelques fonctions à cet effet. Cependant, certaines variables 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. sous la forme sortie par la commande set était:

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

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 une invite de shell interactive (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 articles sur ce sujet. Pour cette commande spécifique pour imprimer les définitions de variables., Et qui ne nécessite qu'un seul argument, j'ai fait ceci:

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

Ce qui donne la sortie correcte (aucune) et l'état du résultat (faux):

> asv FUNCNAME
> echo $?
1

Cependant, je me sentais toujours obligé de trouver une solution qui fonctionne pour un nombre arbitraire d'arguments.

Une solution générale pour passer des arguments arbitraires à une commande alias 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".

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

crobc1
la source
3

Une fois que j'ai fait un projet amusant et je l'utilise toujours. Cela montre de l'animation alors que je copie des fichiers via la cpcommande coz cpne montre rien et c'est un peu frustrant. J'ai donc fait cet alias

alias cp="~/SCR/spiner cp"

Et c'est le script 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

C'est comme ça

entrez la description de l'image ici

Animation à vélo)

entrez la description de l'image ici

Ivan
la source
2

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 pendant l'exécution de l'alias et l'échappement de $ ne fonctionne pas non plus. Comment 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_profileou ~/.zshrcfichier.

Dans votre cas, cela fonctionnera

function trash() { mv $@ ~/.Trash; }
Ahmad Awais
la source
Je ne comprends pas ton idée. Je pense que ce n'est pas important lorsque les arguments sont interprétés. Aliase accepte autant de paramètres que vous le souhaitez à la fin.
Timo
Mais il vaut mieux le faire avec des fonctions. Les alias ne sont pas destinés à cela.
Ahmad Awais
1

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

Pour être complet et parce que cela peut être utile (syntaxe légèrement plus légère), on peut noter que lorsque le ou les paramètres suivent l'alias, ils peuvent toujours être utilisés (bien que cela ne répondrait pas aux exigences de l'OP). C'est probablement plus facile à démontrer avec un exemple:

alias ssh_disc='ssh -O stop'

me permet de taper smth like ssh_disc myhost, qui est développé comme prévu: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 ...)

sxc731
la source
1

Les fonctions et les alias peuvent utiliser des paramètres comme d'autres l'ont montré ici. De plus, je voudrais souligner quelques autres aspects:

1. la fonction s'exécute dans sa propre portée, alias partage la portée

Il peut être utile de connaître cette différence dans les cas où vous devez cacher ou exposer quelque chose. Cela suggère également qu'une fonction est le meilleur choix pour l'encapsulation.

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 

Production:

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. le script wrapper est un meilleur choix

Il m'est arrivé plusieurs fois qu'un alias ou une fonction ne soit pas trouvé lors de la connexion viassh ou impliquant la commutation de noms d'utilisateurs ou d'un environnement multi-utilisateurs. Il y a des trucs et astuces avec le sourcing de fichiers dot, ou celui-ci avec l'alias: permet à cet alias suivant de fonctionner comme prévu (notez l'espace supplémentaire dedans ). Cependant, un script wrapper fonctionne mieux qu'une fonction ou un alias dans des cas comme celui-ci. Le principal avantage d'un script wrapper est qu'il est visible / exécutable pour le chemin prévu (c'est-à-dire / usr / loca / bin /) où en tant que fonction / alias doit être obtenu avant de pouvoir être utilisé. Par exemple, vous placez une fonction dans un ~ / .bash_profile ou ~ / .bashrc pour , mais passez ensuite à un autre shell (c'est-à-dire ) alors la fonction n'est plus visible. Ainsi, en cas de doute, un script wrapper est toujours la solution la plus fiable et portable.alias sd='sudo 'alias install='sd apt-get install'sd='sudo 'bashzsh

biocyberman
la source
1
Pourquoi pensez-vous que la version de la fonction ne fonctionne pas?
tripleee
@tripleee. J'ai édité le post pour le rendre plus lisible. Sous le titre "1. alias fonctionne, fonction ...", j'ai expliqué pourquoi une version de fonction ne fonctionne pas. Et peut-être pour répondre directement à la question, la fonction introduit une nouvelle portée où l'alias ne le fait pas.
biocyberman du
Vous dites que ça ne marche pas mais je ne vous crois pas. sourcedans une fonction fonctionne très bien.
tripleee
1
f () { source /tmp/nst; }fait exactement ce que j'attends. Peut-être que vous avez PATHtort, alors ça tourne mal activateou quelque chose; mais l'exécution sourced'une fonction fonctionne très bien.
tripleee
1
BTW, re: en utilisant le functionmot - clé dans votre définition, voir wiki.bash-hackers.org/scripting/obsolete - function funcname {est une ancienne syntaxe ksh prise en charge par bash pour une compatibilité descendante avec les shells pré-POSIX, alors que funcname() {c'est une syntaxe officielle standardisée POSIX. function funcname() {est une incompatibilité des deux qui n'est pas compatible avec l'ancien ksh ou compatible avec POSIX sh, et qu'il est donc préférable d'éviter.
Charles Duffy
1

Voici l'exemple:

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

Très important:

  1. Il y a un espace après {et avant }.
  2. Il y a un ;après chaque commande dans l'ordre. Si vous oubliez cela après la dernière commande, vous verrez à >la place une invite!
  3. L'argument est placé entre guillemets comme "$1"
Shital Shah
la source
2
Il n'est pas nécessaire de créer un alias pour une fonction, utilisez simplement la fonction directement.
user3439894
1

Comme cela a déjà été souligné par d'autres, l'utilisation d'une fonction doit être considérée comme la meilleure pratique.

Cependant, voici une autre approche, en tirant parti xargs:

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

Notez que cela a des effets secondaires concernant la redirection des flux.

dirdi
la source
0

Vous n'avez rien à faire, alias le fait automatiquement.

Par exemple, si je veux paramétrer git pull origin master, je peux simplement créer un alias comme suit:

alias gpull = 'git pull origin '

et lorsque vous l'appelez, vous pouvez passer 'master' (le nom de la branche) comme paramètre, comme ceci:

gpull master
//or any other branch
gpull mybranch
KayV
la source
Cela ne répond pas à la question, car l'argument ne peut pas être placé librement, mais seulement à la fin.
dirdi