Faire un alias Bash qui prend un paramètre?
j'utilisais cshell ( csh ), 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.
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
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; }
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 $@
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.
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:
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.
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:
- Rogner les espaces de chaînes: Comment couper les espaces à partir d'un Bash variable?
- lignes réelles: https://stackoverflow.com/a/4296147/2736496
- Alias w/ param: https://stackoverflow.com/a/7131683/2736496 (une autre réponse à cette question)
- HISTIGNORE: https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash
- y/N prompt: https://stackoverflow.com/a/3232082/2736496
- supprimer tous les éléments correspondants de l'historique: https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
- est chaîne nulle/vide: http://tldp.org/LDP/abs/html/comparison-ops.html
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).
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; }
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.
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.
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...)
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