web-dev-qa-db-fra.com

Dans Bash, quand alias, quand écrire un script et quand écrire une fonction?

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.

372
ixtmixilix

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.

246
Kevin

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.

Alias ​​et fonctions ¹

  • L'ensemble du contenu des alias et des fonctions est stocké dans la mémoire du Shell.
  • Une conséquence naturelle de ceci est que les alias et les fonctions peuvent niquement être utilisés par le shell actuel, et non par d'autres programmes que vous pouvez invoquer à partir du shell comme des éditeurs de texte, des scripts ou même des instances enfants du même Coquille.
  • Les alias et les fonctions sont exécutés par le shell actuel, c'est-à-dire qu'ils s'exécutent dans et affectent l'environnement actuel du shell.² Aucun processus distinct n'est nécessaire pour exécuter un alias ou une fonction.

Scripts

  • Les shells ne gardent pas les scripts en mémoire. Au lieu de cela, les scripts sont lus à partir des fichiers où ils sont stockés chaque fois qu'ils sont nécessaires. Si le script est trouvé via un $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.

Application

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.

267
jw013

Je pense que c'est au goût de chacun. Pour moi, la logique va comme ceci:

  • J'essaie d'abord de créer un alias, car c'est le plus simple.
  • Si la chose est trop compliquée pour tenir sur une seule ligne, j'essaie d'en faire une fonction.
  • Lorsque la fonction commence à croître au-delà d'une douzaine de lignes, je la mets dans un script.

Il n'y a vraiment rien pour vous empêcher de faire quelque chose qui fonctionne.

39
phunehehe

C'est au moins partiellement une question de goût personnel. D'un autre côté, il existe des distinctions fonctionnelles claires:

  • alias: ne convient qu'aux remplacements de texte simples, pas d'arguments/paramètres
  • fonctions: facile à écrire/utiliser, capacité de script Shell complète, uniquement disponible dans bash
  • scripts: fonctions plus ou moins similaires, mais disponibles (appelables) en dehors de bash également

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.

15
nohillside

Voici quelques points supplémentaires sur les alias et les fonctions:

  • même nom l'alias et la fonction peuvent coexister
  • l'espace de noms d'alias est recherché premier (voir le premier exemple)
  • alias ne peut pas être (dé) défini dans des sous-coquilles ou un environnement non interactif (voir le deuxième exemple)

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.

11
leden

Quand écrire un script ...

  • Les scripts assemblent les composants logiciels (alias outils, commandes, processus, exécutables, programmes) en composants plus complexes, qui peuvent eux-mêmes être assemblés en composants encore plus complexes.
  • Les scripts sont généralement rendus exécutables pour pouvoir être appelés par leur nom. Lorsqu'il est appelé, un nouveau sous-processus est généré pour que le script s'exécute. Les copies de toutes les variables et/ou fonctions exported sont passées par valeur au script. Les modifications apportées à ces variables ne se propagent pas au script parent.
  • Les scripts peuvent également être chargés (provenant) comme s'ils faisaient partie du script appelant. Ceci est analogue à ce que certaines autres langues appellent "importer" ou "inclure". Lorsqu'elles proviennent, elles s'exécutent dans le cadre du processus existant. Aucun sous-processus n'est généré.

Quand écrire une fonction ...

  • Les fonctions sont des scripts Shell effectivement préchargés. Ils fonctionnent un peu mieux que d'appeler un script séparé, mais seulement s'il doit être lu à partir du disque mécanique. La prolifération actuelle des lecteurs flash, des SSD et de la mise en cache normale de Linux dans les RAM RAM rendent cette amélioration largement non mesurable).
  • Les fonctions sont le principal moyen utilisé par bash pour réaliser la modularité, l'encapsulation et la réutilisation. Ils améliorent la clarté, la fiabilité et la maintenabilité des scripts.
  • Les règles de syntaxe pour appeler une fonction sont identiques à celles de l'appel d'un exécutable. Une fonction portant le même nom qu'un exécutable serait invoquée à la place de l'exécutable.
  • Les fonctions sont locales au script dans lequel elles se trouvent.
  • Les fonctions peuvent être exportées ( copiées par valeur) afin qu'elles puissent être utilisées dans des scripts appelés. Ainsi, les fonctions se propagent uniquement aux processus enfants, jamais aux parents.
  • Les fonctions créent des commandes réutilisables qui sont souvent assemblées dans des bibliothèques (un script avec uniquement des définitions de fonction) pour être obtenues par d'autres scripts.

Quand écrire un alias ...

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 "$@"; }
10
DocSalvager

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.

9
Jan Steinman

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.

7
user unknown

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.

6
Mikel

Juste pour ajouter quelques notes:

  • Seul un script séparé peut être utilisé avec Sudo (comme si vous devez modifier un fichier système), par exemple:
Sudo v /etc/rc.conf  #where v runs vim in a new terminal window;
  • Seuls les alias ou fonctions peuvent remplacer les commandes système sous le même nom (en supposant que vous ajoutez vos répertoires de scripts à la fin de PATH, ce qui, à mon avis, est recommandé pour la sécurité en cas de création accidentelle ou malveillante de script avec un nom identique à une commande système), par exemple:
alias ls='ls --color=auto'  #enable colored output;
  • Les alias et les fonctions prennent moins de mémoire et de temps pour l'exécution, mais prennent du temps à charger (car Shell doit les interpréter tous avant de vous montrer Prompt). Tenez-en compte si vous exécutez régulièrement de nouveaux processus Shell, par exemple:
# 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.

3
corvinus

Ma règle d'or est la suivante:

  • alias - une commande, pas de paramètres
  • fonctions - une commande certains paramètres
  • script - plusieurs commandes, aucun paramètre
2
Michael Durrant

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

1
tjb63

Quand écrire un script

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.

0
D. Ben Knoble

Un exemple de situation dans laquelle vous aimeriez très probablement utiliser un alias.

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

  1. m'amène à un certain répertoire.
  2. définit quelques variables.
  3. imprime des messages sur l'état du répertoire.2

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.

Remarques:

  1. J'ai utilisé un script pour cette tâche et non une fonction non pas parce qu'il est particulièrement long mais parce que je peux le modifier et je n'ai pas besoin de source le fichier après une modification si je veux rafraîchir son utilisation.
  2. Un cas similaire m'est apparu lorsque j'ai créé un script pour recharger tous mes fichiers dot.3
  1. Le script est disponible dans mon dépôt dotfiles sous .bin/.
  2. 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 ensuite ls -l et git status pour me montrer ce qui se passe là-bas.
  3. Ce script est également disponible dans mon référentiel dotfiles sous .bin/ ainsi que.
0
Doron Behar