Il m'a fallu près de 10 ans d'utilisation de Linux pour poser cette question. Il s'agissait d'essais et d'erreurs et d'une navigation Internet aléatoire tard le soir.
Mais les gens ne devraient pas avoir besoin de 10 ans pour cela. Si je débutais avec Linux, je voudrais savoir: Quand alias, quand écrire un script et quand écrire une fonction?
En ce qui concerne les alias, j'utilise des alias pour des opérations très simples qui ne prennent pas d'arguments.
alias houston='cd /home/username/.scripts/'
Cela semble évident. Mais certaines personnes le font:
alias command="bash bashscriptname"
(et ajoutez-le au .bashrc
fichier)
Y a-t-il une bonne raison de le faire? J'essaie vraiment fort, mais je ne peux vraiment pas penser à des circonstances dans lesquelles je voudrais faire cela. Donc, s'il y a un cas Edge où cela ferait une différence, veuillez répondre ci-dessous.
Parce que c'est là que je voudrais simplement mettre quelque chose dans mon CHEMIN et chmod +x
it, ce qui est une autre chose qui est survenue après des années d'essais et d'erreurs Linux.
Ce qui m'amène au sujet suivant. Par exemple, j'ai ajouté un dossier caché (.scripts/
) dans le répertoire personnel de mon CHEMIN en ajoutant simplement une ligne à mon .bashrc
(PATH=$PATH:/home/username/.scripts/
), donc tout ce qui est exécutable là-dedans se termine automatiquement.
Si j'en avais besoin.
Mais je n'en ai pas vraiment besoin, n'est-ce pas? Je ne l'utiliserais que pour les langages qui ne sont pas le Shell, comme Python.
Si c'est le Shell, je peux simplement écrire une fonction dans le même .bashrc
:
funcname () {
somecommand -someARGS "$@"
}
Comme je l'ai dit, j'ai trouvé beaucoup de choses par essais et erreurs. Et je n'ai vraiment vu la beauté des fonctions que lorsque mon ordinateur est mort et j'ai été obligé d'utiliser les ordinateurs des gens autour de moi quand ils ne les utilisaient pas.
Au lieu de déplacer tout un répertoire de scripts d'un ordinateur à l'autre, j'ai fini par remplacer le .bashrc de tous les autres par le mien, car ils n'avaient même jamais apporté une seule modification.
Mais ai-je raté quelque chose?
Alors, que diriez-vous à un utilisateur Linux débutant de quand alias, quand écrire un script et quand écrire une fonction?
Si ce n'est pas évident, je suppose que les personnes qui répondront utiliseront les trois options. Si vous utilisez uniquement des alias, ou uniquement des scripts, ou uniquement des fonctions —ou si vous n'utilisez que des alias et des scripts ou des alias et des fonctions ou des scripts et des fonctions - cette question ne s'adresse pas vraiment à vous.
Un alias ne doit en fait pas (en général) faire plus que changer les options par défaut d'une commande. Ce n'est rien de plus qu'un simple remplacement de texte sur le nom de la commande. Il ne peut rien faire avec des arguments mais les passe à la commande qu'il exécute réellement. Donc, si vous avez simplement besoin d'ajouter un argument au début d'une seule commande, un alias fonctionnera. Des exemples courants sont
# Make ls output in color by default.
alias ls="ls --color=auto"
# make mv ask before overwriting a file by default
alias mv="mv -i"
Une fonction doit être utilisée lorsque vous devez faire quelque chose de plus complexe qu'un alias, mais cela ne serait pas utile en soi. Par exemple, prenez cette réponse sur une question que j'ai posée sur la modification du comportement par défaut de grep
selon qu'il se trouve dans un pipeline:
grep() {
if [[ -t 1 ]]; then
command grep -n "$@"
else
command grep "$@"
fi
}
C'est un exemple parfait d'une fonction car elle est trop complexe pour un alias (nécessitant des valeurs par défaut différentes en fonction d'une condition), mais ce n'est pas quelque chose dont vous aurez besoin dans un script non interactif.
Si vous obtenez trop de fonctions ou des fonctions trop grandes, placez-les dans des fichiers séparés dans un répertoire caché et sourcez-les dans votre ~/.bashrc
:
if [ -d ~/.bash_functions ]; then
for file in ~/.bash_functions/*; do
. "$file"
done
fi
Un script doit être autonome. Il doit avoir une valeur en tant que quelque chose qui peut être réutilisé ou utilisé à plusieurs fins.
Les autres réponses fournissent quelques directives générales douces basées sur les goûts personnels, mais ignorent de nombreux faits pertinents à prendre en compte lors du choix entre les scripts, les fonctions ou les alias.
$PATH
recherche, de nombreux shells stockent un hachage de son nom de chemin en mémoire pour gagner du temps sur le futur $PATH
les recherches, mais c'est l'étendue de l'empreinte mémoire d'un script lorsqu'il n'est pas utilisé.Les scripts peuvent être invoqués de plusieurs manières plus que les fonctions et les alias. Ils peuvent être passés en argument à un interprète, comme sh script
, ou appelé directement en tant qu'exécutable, auquel cas l'interpréteur de la ligne Shebang (par exemple #!/bin/sh
) est invoqué pour l'exécuter. Dans les deux cas, le script est exécuté par un processus d'interpréteur distinct avec son propre environnement distinct de celui de votre shell, dont l'environnement le script ne peut en aucun cas affecter. En effet, l'interpréteur Shell n'a même pas à faire correspondre le shell appelant. Comme les scripts invoqués de cette manière semblent se comporter comme n'importe quel exécutable ordinaire, ils peuvent être utilisés par n'importe quel programme.
Enfin, un script peut être lu et exécuté par le shell actuel avec .
, ou dans certains shells, source
. Dans ce cas, le script se comporte un peu comme une fonction qui est lue à la demande au lieu d'être constamment conservée en mémoire.
Compte tenu de ce qui précède, nous pouvons proposer des directives générales pour faire de quelque chose un script ou une fonction/alias.
Est-ce que d'autres programmes que votre Shell doivent pouvoir l'utiliser? Si c'est le cas, ce doit être un script.
Voulez-vous seulement qu'il soit disponible à partir d'un shell interactif? Il est courant de vouloir changer le comportement par défaut de nombreuses commandes lors de leur exécution interactive sans affecter les commandes/scripts externes. Dans ce cas, utilisez un alias/fonction défini dans le fichier rc "mode interactif uniquement" du shell (pour bash
c'est .bashrc
).
Doit-il changer l'environnement du Shell? Une fonction/alias ou un script source sont des choix possibles.
Est-ce quelque chose que vous utilisez fréquemment? Il est probablement plus efficace de le garder en mémoire, alors faites-en une fonction/alias si possible.
Inversement, est-ce quelque chose que vous n'utilisez que rarement? Dans ce cas, cela n'a aucun sens de l'avoir en mémoire de porc quand vous n'en avez pas besoin, alors faites-en un script.
¹ Bien que les fonctions et les alias présentent des différences importantes, ils sont regroupés car les fonctions peuvent faire tout ce que les alias peuvent faire. Les alias ne peuvent pas avoir de variables locales ni traiter d'arguments, et ils ne sont pas pratiques pour plus d'une ligne.
² Chaque processus en cours d'exécution dans un système Unix a un environnement composé d'un tas de variable=value
paires qui contiennent souvent des paramètres de configuration globale, comme LANG
pour les paramètres régionaux par défaut et PATH
pour spécifier le chemin de recherche exécutable.
Je pense que c'est au goût de chacun. Pour moi, la logique va comme ceci:
Il n'y a vraiment rien pour vous empêcher de faire quelque chose qui fonctionne.
C'est au moins partiellement une question de goût personnel. D'un autre côté, il existe des distinctions fonctionnelles claires:
En regardant les scripts Shell que j'ai fait ces dernières années, j'ai plus ou moins arrêté d'écrire des alias (car ils ont tous tendance à devenir des fonctions au fil du temps) et à ne faire des scripts que s'ils doivent également être disponibles à partir d'environnements non-bash.
PS: comme pour alias command="bash bashscriptname"
Je ne vois aucune raison de faire ça. Même si bashscriptname
n'est pas dans $ PATH, un simple alias c=/path/to/script
serait suffisant.
Voici quelques points supplémentaires sur les alias et les fonctions:
Par exemple:
alias f='echo Alias'; f # prints "Alias"
function f { echo 'Function'; }; f # prints "Alias"
unalias f; f # prints "Function"
Comme nous pouvons le voir, il existe des espaces de noms distincts pour les alias et les fonctions; plus de détails peuvent être trouvés en utilisant declare -A -p BASH_ALIASES
et declare -f f
, qui imprime leurs définitions (les deux sont stockées en mémoire).
Exemple montrant les limitations des alias:
alias a='echo Alias'
a # OK: prints "Alias"
eval a; # OK: prints "Alias"
( alias a="Nested"; a ); # prints "Alias" (not "Nested")
( unalias a; a ); # prints "Alias"
bash -c "alias aa='Another Alias'; aa" # ERROR: bash: aa: command not found
Comme nous pouvons le voir, les alias ne sont pas emboîtables, contrairement aux fonctions. De plus, leur utilisation est limitée aux sessions interactives.
Enfin, notez que vous pouvez avoir un calcul arbitraire dans un alias en déclarant une fonction a immédiatement en l'appelant, comme ceci:
alias a_complex_thing='f() { do_stuff_in_function; } f'
qui est déjà largement utilisé dans le cas des alias Git. L'avantage de le faire par rapport à la déclaration d'une fonction est que votre alias ne peut pas être simplement écrasé par la source (ou en utilisant .
) un script qui déclare une fonction du même nom.
Quand écrire un script ...
export
ed sont passées par valeur au script. Les modifications apportées à ces variables ne se propagent pas au script parent.Quand écrire une fonction ...
Quand écrire un alias ...
~/.profile
ou ~/.bashrc
.Dans les scripts tels que les scripts de bibliothèque, un alias pour une fonction est parfois nécessaire, par exemple lorsqu'une fonction est renommée mais qu'une compatibilité descendante est requise. Cela peut être accompli en créant une fonction simple avec l'ancien nom qui transmet tous ses arguments à la nouvelle fonction ...
# A bash in-script 'alias'
function oldFunction () { newFunction "$@"; }
Une autre chose que je ne crois pas a été évoquée: une fonction s'exécute dans le contexte du processus d'appel, tandis qu'un script opère un nouveau Shell.
Cela peut être important pour les performances - une fonction est plus rapide, car elle ne fait pas fork()
et exec()
. Dans des circonstances normales, la différence est insignifiante, mais si vous déboguez un système qui est à court de mémoire et qui débite des pages, cela pourrait faire une grande différence.
De plus, si vous souhaitez modifier votre environnement Shell actuel, vous devez utiliser une fonction. Par exemple, une fonction peut modifier la recherche de commande $PATH
pour le shell actuel, mais pas un script, car il fonctionne sur une copie fork/exec de $PATH
.
Script et alias et script et fonction ne s'excluent pas mutuellement. Vous pouvez stocker des alias et des fonctions dans des scripts.
Les scripts ne sont que du code rendu persistant. Les fonctions et alias utiles que vous souhaitez utiliser à l'avenir sont stockés dans des scripts. Cependant, un script est souvent une collection de plusieurs fonctions.
Puisque les alias ne sont pas paramétrés, ils sont très limités; généralement pour définir certains paramètres par défaut.
A la fonction est une unité de code distincte, un concept bien défini de quelques lignes de code qui ne peuvent pas être séparées en parties plus petites et utiles; celui qui peut être réutilisé directement ou autre par d'autres fonctions.
S'il doit être très rapide, faites-en un alias ou une fonction.
S'il doit être utilisable en dehors de votre shell préféré, faites-en un script.1
S'il prend des arguments, faites-en une fonction ou un script.
S'il doit contenir des caractères spéciaux, faites-en un alias ou un script.2
S'il doit fonctionner avec Sudo, faites-en un alias ou un script.3
Si vous souhaitez le modifier facilement sans vous déconnecter ni vous connecter, un script est plus simple.4
Notes de bas de page
1 Ou faites-en un alias, mettez-le dans ~/.env
Et mettre export ENV="$HOME/.env"
, mais c'est compliqué de le faire fonctionner de manière portable.
2 Les noms de fonction doivent être des identifiants, ils doivent donc commencer par une lettre et ne peuvent contenir que des lettres, des chiffres et des traits de soulignement. Par exemple, j'ai un alias alias +='pushd +1'
. Ça ne peut pas être une fonction.
3 Et ajoutez l'alias alias Sudo='Sudo '
. Idem toute autre commande telle que strace
, gdb
, etc. qui prend une commande comme premier argument.
4 Voir aussi: fpath. Bien sûr, vous pouvez également faire source ~/.bashrc
ou similaire, mais cela a souvent d'autres effets secondaires.
Juste pour ajouter quelques notes:
Sudo v /etc/rc.conf #where v runs vim in a new terminal window;
alias ls='ls --color=auto' #enable colored output;
# pressing key to open new terminal # waiting for a few seconds before Shell Prompt finally appears.
En dehors de cela, vous pouvez utiliser la forme la plus simple possible, c'est-à-dire d'abord considérer l'alias, puis la fonction, puis le script.
Ma règle d'or est la suivante:
Dans un environnement multi-utilisateurs (ou multi-sysamin), j'utilise des scripts pour tout, même si cela finit simplement par être un court wrapper 'exec quelque chose ....'.
Bien sûr, il est techniquement plus lent/moins efficace qu'un alias ou une fonction, mais cela n'a presque jamais d'importance - et à condition qu'il soit sur le chemin, un script fonctionne toujours.
Votre fonctionnalité peut être appelée à partir de cron, à partir de quelque chose avec un environnement réduit ou modifié comme Sudo ou env, ou l'utilisateur peut simplement utiliser un Shell différent pour vous - tout ou qui est susceptible de casser un alias ou une fonction.
Si vous avez quelque chose de sensible aux performances, gérez-le comme un cas spécial, ou mieux encore, considérez-le comme un déclencheur à réécrire dans un langage de script plus fonctionnel.
Si nous parlons de fonctionnalités qui ne seront utilisées que dans d'autres scripts, vous pouvez également envisager de définir un shell standard et d'écrire un script de bibliothèque de fonctions qui peut simplement l'être. j'ai sourced à tous les autres scripts.
T
Lorsque vous souhaiterez peut-être exécuter la commande à partir d'un outil autre que le shell.
Cela inclut vim (pour moi): ayant écrit des filtres et d'autres programmes en tant que scripts, je peux faire quelque chose comme :%!my-filter
pour filtrer un fichier via le programme depuis mon éditeur.
Si my-filter
était une fonction ou un alias, ce ne serait pas possible.
Je sais que c'est un ancien article mais je voudrais souligner une situation où j'ai presque dû utiliser une combinaison d'alias avec un script et j'ai choisi ne pas utiliser de fonction.
J'ai un script dans ~/.bin/
appelé setup
qui fait ce qui suit:1
Le fait est que si je courais simplement setup <project-name>
Je n'aurais pas défini ces variables et je n'aurais pas du tout pu accéder au répertoire. La solution que j'ai trouvée la meilleure était d'ajouter ce script à PATH
et d'ajouter alias setup=". ~/.bin/setup"
à ~/.bashrc
ou peu importe.
- Le script est disponible dans mon dépôt dotfiles sous
.bin/
.- A propos du script : Je donne à ce script un argument qui est un nom pour le projet que j'ai défini à l'avance. Ensuite, le script sait m'apporter dans le bon répertoire en fonction d'un certain fichier
csv
. Les variables qu'il définit sont extraites du makefile de ce répertoire. Le script s'exécute ensuitels -l
etgit status
pour me montrer ce qui se passe là-bas.- Ce script est également disponible dans mon référentiel dotfiles sous
.bin/
ainsi que.