Script Shell modèles
Quelles seraient vos suggestions pour une bonne bash/ksh modèle de script pour l'utiliser comme un standard pour tous les nouveaux scripts?
J'ai l'habitude de commencer (après la #!
ligne) avec une commenté en-tête avec un nom de fichier, le synopsis, l'utilisation, les valeurs de retour, auteur(s), changelog et s'inscrivait dans 80-char lignes.
Tous les documents que j'ai commencer avec double hachage symboles ##
donc je peux grep pour eux facilement et local var noms sont précédés par "__".
Toutes les autres pratiques exemplaires? Des conseils? Les conventions de nommage? Quid des codes de retour?
Commentaires sur la version de contrôle : nous l'utilisation de SVN, mais d'un autre département de l'entreprise dispose d'un repo et c'est de leur script. Comment puis-je savoir qui contacter en cas de questions si il n'y a pas de @info auteur? À l'aide des entrées semblables à la documentation javadoc a un certain mérite, même dans le shell contexte, à mon humble avis, mais j'ai peut-être tort.
- Auteur(s)? Changelog? Obtenir un système de contrôle de version!
- Je ne suis pas convaincu que l'utilisation d'un
__
préfixe pour les noms de variables locales est bénéfique.
Vous devez vous connecter pour publier un commentaire.
J'élargirai Norman, la réponse à 6 lignes, et le dernier de ceux-ci est vide:
La troisième ligne est une version d'identification de contrôle de la chaîne - c'est en fait un hybride avec un SCC marqueur '
@(#)
" qui peuvent être identifiés par l' (CSSC) programmewhat
et un RCS chaîne de version qui est développée lorsque le fichier est placé sous le RCS, le défaut VCS-je utiliser pour mon usage privé. Le RCS programmeident
reprend la forme développée de$Id$
, qui pourrait ressembler à$Id: mkscript.sh,v 2.3 2005/05/20 21:06:35 jleffler Exp $
. La cinquième ligne me rappelle que le script doit avoir une description de son but au top; je remplacer le mot avec une description du script (c'est pourquoi il n'y a pas côlon après, par exemple).Après cela, il n'y a pratiquement rien de standard pour un script shell. Il existe des fragments qui apparaissent, mais pas de standard fragment qui apparaît dans chaque script. (Ma discussion suppose que les scripts sont écrits en Bourne, Korn, ou POSIX (Bash) shell notations. Il y a tout un débat séparé sur le pourquoi personne y mettre de C Shell dérivés après la
#!
sigil est vivre dans le péché.)Par exemple, ce code apparaît dans une forme ou sous une chaque fois qu'un script crée intermédiaire (temporaire) des fichiers:
La première ligne choisit un répertoire temporaire par défaut /tmp si l'utilisateur n'a pas spécifié une alternative ($TMPDIR est très largement reconnu et est normalisé par la norme POSIX). Il crée alors un préfixe de nom de fichier y compris l'ID de processus. Ce n'est pas une mesure de sécurité; c'est une simple simultanéité mesure, la prévention de plusieurs instances du script à partir de piétiner les uns sur les autres données. (Pour la sécurité, l'utilisation non-prévisible des noms de fichiers dans un répertoire.) La deuxième ligne s'assure que le "
rm
" et "exit
" les commandes sont exécutées si le shell reçoit des signaux SIGHUP (1), SIGINT (2), SIGQUIT (3), SIGNAL (13) ou SIGTERM (15). Le "rm
commande supprime tous les fichiers intermédiaires qui correspondent le modèle; leexit
de commande garantit que l'état est non nulle, ce qui indique un type de l'erreur. Le "trap
'de 0 signifie que le code est exécuté si le shell quitte pour une raison quelconque, il couvre la négligence dans la section marquée "vrai travail". Le code à la fin, alors supprime tous les survivants des fichiers temporaires, avant soulever la trappe de sortie, et enfin se termine avec un zéro (succès) d'état. Clairement, si vous voulez sortir avec un autre statut, vous pouvez peut - assurez-vous de mettre dans une variable avant l'exécution de larm
ettrap
lignes, et ensuite utiliserexit $exitval
.J'ai l'habitude d'utiliser les options suivantes pour supprimer le chemin d'accès et le suffixe du script, donc je peux l'utiliser
$arg0
lors de la déclaration des erreurs:J'ai souvent l'utilisation d'une fonction shell pour signaler des erreurs:
Si il y a un seul ou peut-être erreur deux sorties, je ne vous embêtez pas avec la fonction; s'il y a plus, je le fais parce qu'il simplifie le codage. J'ai également créer plus ou moins élaborées, les fonctions appelées
usage
de donner le résumé de comment utiliser la commande - encore une fois, seulement si il y a plus d'un endroit où il sera utilisé.Un autre assez standard fragment est une option de l'analyse de la boucle, à l'aide de la
getopts
shell intégré:ou:
Les guillemets autour de "$OPTARG" gérer les espaces dans les arguments. Le Dflag est cumulatif, mais la notation utilisée ici perd la trace de places dans les arguments. Il y a (non-standard) des moyens pour contourner ce problème, trop.
Le premier quart de notation fonctionne avec n'importe quel shell (ou à faire si j'ai utilisé arrière-tiques au lieu de"
$(...)
'. La seconde fonctionne moderne de coquillages; il pourrait même être une alternative avec des crochets à la place des parenthèses, mais cela fonctionne si je n'ai pas pris la peine de définir ce qu'il est.Un dernier truc, pour l'instant, c'est que j'ai souvent les deux GNU et de la non-version GNU de programmes autour, et je veux être en mesure de choisir qui je utiliser. Beaucoup de mes scripts, par conséquent, l'utilisation de variables telles que:
Et puis, quand j'ai besoin d'invoquer Perl ou
sed
, le script utilise$PERL
ou$SED
. Cela m'aide quand quelque chose se comporte différemment - je peux choisir la version opérationnelle - ou tout en développant le script (je peux ajouter de débogage uniquement les options de la commande, sans modifier le script). (Voir Shell paramètre d'extension pour plus d'informations sur le${VAR:=value}
et liées à des notations.)${VAR:=file}
signifie que si$VAR
est réglé à une valeur non vide, alors l'utilisation de cette valeur, mais si$VAR
n'est pas définie ou est vide, alors l'utilisation de la valeurfile
, et de définir$VAR
à cette valeur. Donc, c'est un peu comme (mais beaucoup plus court que):[ -z "$VAR" ] && VAR=file; echo $VAR
.- Je utiliser le premier ensemble de ## lignes pour l'utilisation de la documentation. Je ne me souviens pas où j'ai vu ce.
cd
n'importe où et$0
n'est pas un nom absolu. J'avais opter pour l'utilisation de la fonction de() à fait echo/printf/chat le message d'utilisation.Tout le code qui va être libéré dans la nature doit avoir la suite de court-tête:
De tenir un journal des modifications allant dans le code des en-têtes est un retour à partir de quand les systèmes de contrôle de version ont été terriblement gênant. Une date de dernière modification montre comment quelqu'un vieux le script est.
Si vous allez être en s'appuyant sur bashisms, utilisez #!/bin/bash , pas de /bin/sh, car le poisson est la POSIX invocation du shell. Même si /bin/sh points de bash, de nombreuses fonctionnalités sera désactivée si vous l'exécutez à l'aide de /bin/sh. La plupart des distributions Linux ne prendra pas les scripts qui reposent sur bashisms, essayez d'être portable.
Pour moi, les commentaires dans les scripts shell sont une sorte de stupide, à moins qu'ils lisent quelque chose comme:
Script Shell est si simple que (à moins que votre écriture d'une manifestation à enseigner à quelqu'un comment faire) le code presque toujours élimine lui-même.
Quelques coquilles n'aime pas être nourris tapé "locale" des variables. Je crois que, à ce jour, Busybox (commune de sauvetage shell) est l'un d'entre eux. Faire GLOBALS_OBVIOUS au lieu de cela, il est beaucoup plus facile à lire, surtout lors du débogage à l'aide de /bin/sh-x ./script.sh.
Ma préférence personnelle est de laisser la logique de parler pour lui-même et de minimiser le travail de l'analyseur. Par exemple, beaucoup de gens pourrait écrire:
Où je venais:
De même, quelqu'un pourrait écrire:
... où j'avais:
La seule fois que j'ai utiliser les classiques if /then /else est si il y a une autre chose-si à jeter dans le mélange.
Une horrible fou exemple de très bon portable shell code peut être étudié par l'affichage de "configurer" le script dans la plupart des logiciels libres que d'utiliser autoconf. Je dis fou à cause de ses 6300 lignes de code qui s'adresse à tous les systèmes connus de l'homme qui a un UNIX shell. Vous ne voulez pas ce genre de ballonnement, mais il est intéressant d'étudier les différents portabilité des hacks à l'intérieur.. comme le fait d'être agréable à ceux qui pourraient le point de /bin/sh pour zsh 🙂
Le seul autre conseil que je puisse donner est de regarder votre expansion dans l'ici-docs, c'est à dire
... va élargir $nom, quand vous voulez probablement pour laisser la variable en place. Résoudre ce via:
qui laissera $nom d'une variable, au lieu de l'élargir.
Je recommande fortement à apprendre à utiliser un piège pour les signaux .. et faire usage de ces gestionnaires comme code réutilisable. Raconter l'exécution d'un script à ralentir avec un simple signal SIGUSR1 est très pratique 🙂
La plupart des nouveaux programmes que j'écris (qui sont un outil de ligne de commande orienté) au départ comme des scripts shell, son une grande manière de prototype outils UNIX.
Vous aimerez aussi la SHC script shell compilateur, découvrez-le ici.
C'est la tête que j'utilise pour mon script shell (bash ou ksh).
C'est un
man
ressemblent et il est utilisé pour afficher l'utilisation de la() et.Et ici est l'utilisation des fonctions pour aller avec:
Voici ce que vous devriez obtenir:
Vous pouvez obtenir le plein modèle de script ici: http://www.uxora.com/unix/shell-script/18-shell-script-template
Permettant la détection de l'erreur, il est beaucoup plus facile de détecter les problèmes dans le script de début:
Sortie de script sur la première erreur. De cette façon, vous éviter de continuer à faire quelque chose qui dépendait de quelque chose de plus haut dans le script, peut-être de se retrouver avec un étrange état du système.
Traiter des références à annuler les variables comme des erreurs. Très important pour éviter des choses comme
rm -you_know_what "$var/"
avec un unset$var
. Si vous savez que la variable peut être défini, et c'est une situation sûre, vous pouvez utiliser${var-value}
d'utiliser une valeur différente si c'est unset ou${var:-value}
d'utiliser une valeur différente si c'est unset ou vide.Il est facile de faire l'erreur de l'insertion d'un
>
où que vous vouliez insérer<
, et d'écraser certains fichiers qui vous destinée à le lire. Si vous avez besoin de tabasser un fichier dans votre script, vous pouvez désactiver cette avant de la ligne et de le réactiver par la suite.Utiliser le premier code de sortie non nulle (le cas échéant) d'un ensemble de canalisations de commande que le code de sortie de l'ensemble des commandes. Cela rend plus facile à déboguer les canalisations de commandes.
Éviter que votre
/foo/*
glob est interprété littéralement si il n'y a pas les fichiers correspondant à cette expression.Vous pouvez combiner l'ensemble de ces deux lignes:
Mon bash modèle est comme ci-dessous(à régler dans ma configuration de vim):
Je dirais
et c'est tout. Poids lourd de bloquer les commentaires pour les scripts shell? Je reçois les zizis.
Suggestions:
De la Documentation devrait être données ou de code, pas de commentaires. Au moins un
usage()
fonction. Jetez un oeil à la façon dont ksh et les autres AST outils se documenter à l'aide de --l'homme d'options sur chaque commande. (Ne peut pas le lien car le site web est en panne).Déclarer des variables locales à
typeset
. C'est ce qu'il est. Pas besoin de méchant souligne.Ce que vous pouvez faire est de faire un script qui crée un en-tête pour un script & et ont auto ouvrir dans votre éditeur de texte favori. J'ai vu un gars faire que sur ce site:
http://code.activestate.com/recipes/577862-bash-script-to-create-a-header-for-bash-scripts/?in=lang-bash
Généralement, j'ai un peu de conventions de j'aime pour coller à pour chaque script que j'écris.
J'écris tous les scripts avec l'hypothèse que d'autres personnes puisse les lire.
Je commence tous les script avec mon en-tête,
J'utilise que le format de date, pour faciliter grep/recherche.
J'utilise le '[' accolades pour indiquer le texte doivent entrer eux-mêmes.
si elles se produisent à l'extérieur d'un commentaire, j'ai essayer de démarrer avec '#['.
De cette façon, si quelqu'un colle comme il est, il ne sera pas confondu avec entrée ou un test de commandement. Vérifiez la section de l'utilisation sur un homme, pour voir ce style comme un exemple.
Quand je veux commenter une ligne de code, j'utilise un '#'. Quand je fais un commentaire, une remarque, j'utilise un double '##'. Le
/etc/nanorc
utilise cette convention. Je trouve qu'il est utile, pour différencier un commentaire qui a été choisi de ne pas les exécuter; les versets un commentaire qui a été créé comme une note.Toutes mes variables shell, je préfère le faire dans les BOUCHONS. J'essaie de garder entre 4 et 8 caractères, sauf si nécessaire. Les noms se rapportent, le mieux possible avec leur utilisation.
J'ai aussi toujours sortie avec 0 en cas de succès, ou un 1 pour les erreurs. Si le script a beaucoup de différents types d'erreurs (et le fait d'aider quelqu'un, ou qui pourrait être utilisée dans le code d'une certaine façon), je choisirais une documenté séquence de plus de 1.
En général, les codes de sortie ne sont pas strictement appliquées dans le monde *nix. Malheureusement, je n'ai jamais trouvé un bon numéro de programme.
J'aime traiter les arguments de façon standard. Je préfère toujours getopts, à getopt. Je ne fais jamais certains hack avec de "lire" des commandes et des instructions if. J'aime également utiliser l'instruction du cas, afin d'éviter imbriquée fi. J'utilise une traduction de script pour les longs options --help moyen -h pour getopts. J'écris tous les scripts dans bash (si accepté) ou générique sh.
Je n'ai JAMAIS utiliser bash interpréter les symboles (ou tout interprété symbole) dans les noms de fichier ou n'importe quel nom pour cette question.
plus précisément... "' ` $ & * # () {} [] -, j'utilise _ pour les espaces.
Rappeler, ce ne sont que des conventions. Les meilleures pratiques, de grossier, mais parfois, vous êtes forcé à l'extérieur des lignes. Le plus important est d'être cohérent à travers et au sein de vos projets.