Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).

#1 05-02-2015 00:00:45

sogal
Black Metal Modo
Distrib. : Debian Testing
Noyau : 4.7
(G)UI : Gnome
Inscription : 09-05-2013
Site Web

SCRIPT SHELL: Bonnes pratiques:

Bonsoir à tous,

Suite à certains posts relatifs aux scripts shell, j'ai trouvé intéressant de discuter et lister les bonnes pratiques à mettre en place lors de la rédaction de scripts SHELL.
L'excellent tutoriel d'Hypathie sur le sujet en liste quelqu'uns.
Le but de ce post est donc de comparer nos expériences, de corriger de fausses idées et d'améliorer nos codes et leur portabilité.
Si ça prend forme et qu'il y a matière, je propose par la suite de compiler le tout dans un tutoriel dédié.

Je commence donc:

Ligne SheBang:
On employera systématiquement cette ligne afin d'indiquer l'interpréteur à utiliser:

#!/bin/sh


#!/bin/bash



En-tête et commentaires:
Rien de plus difficile de reprendre un script, soit longtemps après sa rédaction, soit le travail d'un autre et de ne pas savoir rapidement le but du script ou certaines lignes de code.
Pour cela un en-tête est fort utile, même sur des scripts apparemment court et simple.
Un exemple:


######################################
# Nom du script
# Utilité: ce script sert à faire pousser des fleurs
# Usage: script -option1 -option2 ... (le cas échéant)
# Auteur: Johny BIGOUD <j.bigoud@flowerpower.org>
# Mise à jour le: 00/00/0000
######################################
 


Pour les commentaires, leur but n'est pas n'expliquer chaque élément du code mais d'en expliquer, synthétiquement l'objectif:


# Copier les fichiers AVI de telechargement vers video:
rep="/home/johny/videos/"
for file in $(find ~/telechargement/ -type f -name *.avi)
do
    cp "$file" "$rep"
done
 


Pour les commentaires longs, j'ai vu une syntaxe que j'apprécie:


#   Ceci est un commentaire de code s'étalant sur plusieurs lignes
#+ et comme j'essaye d'écrire des scripts propres, je m'efforce de
#+ ne pas rédiger des lignes trop longues qui s'afficheraient mal
#+ sur de petits terminaux.
 



Protection des variables:
Lors de l'utilisation de variables, il est important de penser à les encadrer de "" afin que son contenu (caractères blancs notamment) n'en perturbe pas l'évalution:


sogal 22:35:41: ~ > var="salut les amis"
sogal 22:36:31: ~ > if [ $var = "salut les amis" ] ; then echo "OK" ; fi
bash: [: trop d'arguments
sogal 22:36:34: ~ > if [ "$var" = "salut les amis" ] ; then echo "OK" ; fi
OK
 


On voit ici que l'évaluation d'une variable non protégée contenant des espaces échoue.

Invocation de commandes:
Lors de l'invocation d'une commande dont le résultat est destiné à être affecté à une variable par exemple, on utilisera préférentiellement la syntaxe $(commande) au lieu de `commande`:

A vous la suite si vous le voulez bien, sinon je continuerai plus tard au gré de mes lectures et expérimentations.
Je serais notamment intéressé qu'un adepte des scripts shell partage ses connaissances des bonnes pratiques dans le cadre de la rédaction de fonctions.

Dernière modification par sogal (19-02-2015 10:30:37)


Machine perso : Thinkpad x230 Debian Stretch | Machine pro : Thinpad T450 openSUSE Leap 42.2

Hors ligne

#2 05-02-2015 00:52:05

captnfab
Admin-Girafe
Lieu : /dev/random
Distrib. : Debian Stretch/Sid/Rc-Buggy
Noyau : Linux (≥ 4.3)
(G)UI : i3-wm (≥ 4.11)
Inscription : 07-07-2008
Site Web

Re : SCRIPT SHELL: Bonnes pratiques:

À propos du #!.
- Il doit impérativement être en première ligne
- Il doit impérativement être présent pour un script exécutable
- On ne doit utiliser /bin/sh comme interpréteur que si notre script est effectivement POSIX, on ne doit pas utiliser /bin/sh si notre script utilise des bashismes ou des dashismes
- Utiliser des bashismes n'est pas interdit, mais il faut alors indiquer bash comme interpréteur, et le script ne peut fonctionner que sur les machines ayant bash d'installé

Donc, de mon point de vue, la bonne pratique consiste à écrire du code posix et à utiliser /bin/sh comme interpréteur, mais faire du bash en indiquant /bin/sh comme interpréteur, c'est pire que faire du posix et indiquer bash comme interpréteur smile

À propos du «  for file in $(find ~/telechargement/ -type f -name *.avi) »
C'est une mauvaise pratique. Pourquoi ? Parce qu'un nom de fichier (et a fortiori un chemin) peut contenir des espaces, et même des retours à la ligne.
On préférera dans ce cas une syntaxe avec un -exec / -execdir.

De même, le « while read i; do … done » ne devrait pas être utilisé pour lire des noms de fichiers, pour les même raisons.

captnfab,
Association Debian-Facile, bépo.
TheDoctor: Your wish is my command… But be careful what you wish for.

Hors ligne

#3 05-02-2015 10:19:08

enicar
Membre
Lieu : Grenoble
Distrib. : debian/sid
Noyau : Linux 4.8.10
(G)UI : openbox
Inscription : 26-08-2010

Re : SCRIPT SHELL: Bonnes pratiques:

@captnfab

pour qu'un for fonctionne correctement avec tous le caractères dans les noms de fichiers il faut utiliser des guillemets, comme cela :


for f in "$(find ~/telechargement/ -type f -name *.avi)"; do
echo "$f"
done
 



Remarque : Je ne sais pas si les retours à la ligne sont correctement gérés… à tester.

Lorsqu'on utilise while read, on peut préciser un délimiteur, le caractère nul est celui qu'il faut choisir pour passer des noms de fichiers.


while read -d "\000" do … done
 


Il faut alors préciser au programme qui fournit les noms de fichiers d'utiliser le caractère nul comme séparateur d'enregistrement. Avec find
on utilisera -print0

remarque: Je ne suis pas sûr de la syntaxe : read -d "\000"


La machine, c'est dépassé ! On va tout remplacer par des humains big_smile

Hors ligne

#4 05-02-2015 11:43:25

sogal
Black Metal Modo
Distrib. : Debian Testing
Noyau : 4.7
(G)UI : Gnome
Inscription : 09-05-2013
Site Web

Re : SCRIPT SHELL: Bonnes pratiques:

captnfab a écrit :


À propos du «  for file in $(find ~/telechargement/ -type f -name *.avi) »
C'est une mauvaise pratique. Pourquoi ? Parce qu'un nom de fichier (et a fortiori un chemin) peut contenir des espaces, et même des retours à la ligne.
On préférera dans ce cas une syntaxe avec un -exec / -execdir.

De même, le « while read i; do … done » ne devrait pas être utilisé pour lire des noms de fichiers, pour les même raisons.


Merci pour ce premier retour, si tu as l'occasion de développer un brin ces 2 points avec un petit exemple de syntaxe correcte, ce serait génial smile


Machine perso : Thinkpad x230 Debian Stretch | Machine pro : Thinpad T450 openSUSE Leap 42.2

Hors ligne

#5 05-02-2015 12:01:29

captnfab
Admin-Girafe
Lieu : /dev/random
Distrib. : Debian Stretch/Sid/Rc-Buggy
Noyau : Linux (≥ 4.3)
(G)UI : i3-wm (≥ 4.11)
Inscription : 07-07-2008
Site Web

Re : SCRIPT SHELL: Bonnes pratiques:

@sogal: oui, j'essaierai si j'ai le temps smile
Mais dans l'idée, une des solutions les plus propres est d'utiliser \0 comme séparateur de fichiers comme l'a indiqué Enicar.

captnfab,
Association Debian-Facile, bépo.
TheDoctor: Your wish is my command… But be careful what you wish for.

Hors ligne

#6 18-02-2015 21:55:40

Guizmo
Membre
Lieu : Mello dans l'Oise
Distrib. : Jessie
Noyau : Linux 3.2.0-4-686-pae
Inscription : 03-02-2015

Re : SCRIPT SHELL: Bonnes pratiques:

Superbe rubrique, très adaptée pour moi, le truc, c'est que ça me donne envie de poser des questions !

for file in $(find ~/telechargement/ -type f -name *.avi)
do
    cp "$f" "$rep"



Dans cet extrait, la variable $f prend sa valeur dans "for FILE", dans "-type F" ? ou dans l'ensemble de ce qu'il y a entre  parenthèses ?
-type désigne quoi exactement ? le genre de fichier utilisé (avi, mp3, jpg ou autre)
ça serait peut-être un peu chi* pour toi, mais est-ce que tu voudrais bien me détailler la signification de chaque éléments ?
ce que je comprends dans les parenthèses : trouve dans Téléchargements des fichiers de -type/nom *.avi ( ça ne fonctionnerait pas si on supprime un des "-type" "f" "-name"? )
C'est un peu dur pour moi, je n'ai pas de mentor Linux ! Mon seul mentor (de taille !) c'est internet smile


Je suis débutant, si à la lecture d'un de mes postes vous avez des suggestions, des liens à me donner ou n'importe quoi qui puisse me faire avancer, n'hésitez pas ! !
Merci smile

Hors ligne

#7 18-02-2015 22:31:23

enicar
Membre
Lieu : Grenoble
Distrib. : debian/sid
Noyau : Linux 4.8.10
(G)UI : openbox
Inscription : 26-08-2010

Re : SCRIPT SHELL: Bonnes pratiques:

euh, le code devrait être :


for file in $(find ~/telechargement/ -type f -name '*.avi')
do
    cp "$file" "$rep"
done
 



Note, la correspondance de la variable « file » utilisé en entrée de boucle avec
celle utilisée dans la boucle, ça ne peut pas marcher autrement.
Aussi, il faut utiliser des apostrophes simples pour protéger le motif shell '*.avi',
sinon c'est le shell qui va l'interpréter et on veut que soit find qui s'en charge.
(Enfin, ça dépend s'il y a des fichiers correspondant au motif *.avi dans le répertoire
courant (find recherche dans une arborescence, alors que le motif shell *.avi ne
correspond qu'aux fichiers du répertoires courant). Ça dépend aussi de ce que vaut
l'option du shell nullglob , positionné dans bash avec la commande interne « shopt ».)

Sinon pour la signification des options de find :

  • -type f: trouver les fichiers normaux

  • -name '*.avi' : dont le nom correspond au motif shell '*.avi'



On peut préciser d'autres types de fichiers à find avec l'option -type. Une liste non exhaustive :

  • d : répertoire

  • l : lien symbolique

  • s : socket



Je te  laisse regarder toi même la page manuelle de find (qui a été traduite en français) avec la commande :


man find
 



Note, la commande man est la commande que tu devrais utiliser tout le temps
pour découvrir l'usage des commandes. Un bon réflexe est de consulter les man
de toutes les commandes que tu utilises wink

Pour terminer, sans le -type f, find pourrait trouver aussi des fichiers qui ne sont
pas normaux, c'est à dire des répertoires, des liens symboliques, des fichiers de
type périphériques, etc…
Après tout dépend de ce que tu veux faire. Je trouve que c'est une bonne idée d'être
le plus précis possible. Enfin, comme l'enfer est pavé de bonnes intentions, la précision
se retourne quelques fois contre nous, il faut alors appliqué le précepte qui veut que le
mieux est l'ennemi du bien wink

Dernière modification par enicar (12-03-2015 18:01:10)


La machine, c'est dépassé ! On va tout remplacer par des humains big_smile

Hors ligne

#8 19-02-2015 07:25:35

chuugar
Membre
Lieu : Nancy, France
Distrib. : Jessie
Noyau : 4.7.2 (compilé)
(G)UI : Openbox
Inscription : 17-08-2012

Re : SCRIPT SHELL: Bonnes pratiques:

En Bash on préfère les variables en majuscule. cool

Vous cherchez une alternative à Google?
Essayez StartPage !

Hors ligne

#9 19-02-2015 09:09:06

enicar
Membre
Lieu : Grenoble
Distrib. : debian/sid
Noyau : Linux 4.8.10
(G)UI : openbox
Inscription : 26-08-2010

Re : SCRIPT SHELL: Bonnes pratiques:

chuugar a écrit :

En Bash on préfère les variables en majuscule. cool



J'ai l'habitude d'utiliser des variables en majuscules pour les variables globales à un script et pour
les variables à exporter dans l'environnement (en bash, il est possible d'exporter des variables en minuscules,
mais je trouve que c'est une très mauvaise pratique).

Autrement, pour une variable qui est local à une boucle for ou à une fonction,
une variable en minuscule est préférable, amha.

Ce n'est peut être pas la pratique recommandée par les puristes de bash, mais bon… wink


La machine, c'est dépassé ! On va tout remplacer par des humains big_smile

Hors ligne

#10 19-02-2015 15:45:33

vv222
Membre
Lieu : Bretagne
Distrib. : GNU/Linux Debian « Sid »
Noyau : >= Linux 4.5.0 (amd64)
(G)UI : Openbox + ROX
Inscription : 18-11-2013
Site Web

Re : SCRIPT SHELL: Bonnes pratiques:

enicar a écrit :

J'ai l'habitude d'utiliser des variables en majuscules pour les variables globales à un script et pour
les variables à exporter dans l'environnement (en bash, il est possible d'exporter des variables en minuscules,
mais je trouve que c'est une très mauvaise pratique).

Autrement, pour une variable qui est local à une boucle for ou à une fonction,
une variable en minuscule est préférable, amha.


Je m’appelle vv222 et je soutiens cette pratique.

https://paste.debian-facile.org//view/36e0052c


Jouer sous Debian ? Facile !

Hors ligne

#11 19-02-2015 18:09:20

enicar
Membre
Lieu : Grenoble
Distrib. : debian/sid
Noyau : Linux 4.8.10
(G)UI : openbox
Inscription : 26-08-2010

Re : SCRIPT SHELL: Bonnes pratiques:

@vv222 les grands esprits se rencontrent wink

La machine, c'est dépassé ! On va tout remplacer par des humains big_smile

Hors ligne

#12 19-02-2015 18:24:52

smolski
administrateur quasi...modo
Lieu : AIN
Distrib. : 8 (jessie) 64 bits + backports
Noyau : 4.6.0-0.bpo.1-amd64
(G)UI : gnome 3.14.1
Inscription : 21-10-2008

Re : SCRIPT SHELL: Bonnes pratiques:

Le médium était concentré
L'assistance était convulsée
La table soudain, a remué
Et l'esprit frappeur a frappé.


C'n'est qu'le p'tit bout d'la queue du chat
Qui vous électrise,
C'n'est qu'le p'tit bout d'la queue du chat
Qui a fait c'bruit là.
Non, l'esprit n'est pas encor' là
Unissons nos fluides
Et recommençons nos ébats
Que le chat gâcha.


big_smile

"Définition d'eric besson : S'il fallait en chier des tonnes pour devenir ministre, il aurait 2 trous du cul." - JP Douillon
"L'utopie ne signifie pas l'irréalisable, mais l'irréalisée." - T Monod (source :  La zone de Siné)
"Je peux rire de tout mais pas avec n'importe qui." - P Desproges
"saque eud dun" (patois chtimi : fonce dedans)

Hors ligne

#13 23-02-2015 11:12:02

Guizmo
Membre
Lieu : Mello dans l'Oise
Distrib. : Jessie
Noyau : Linux 3.2.0-4-686-pae
Inscription : 03-02-2015

Re : SCRIPT SHELL: Bonnes pratiques:

Bonjour à tous
Merci enicar (geek à longue barbe bien-veillant qui ne demande qu'à aider les noobs comme moi ! lol )
Je connais "man" et à peu prêt ttes les commandes de base.
Regarde ce que me renvoie "shopt" :

$ shopt
autocd          off
cdable_vars     off
cdspell         off
checkhash       off
checkjobs       off
checkwinsize    on
cmdhist         on
compat31        off
compat32        off
compat40        off
compat41        off
direxpand       off
dirspell        off
dotglob         off
execfail        off
expand_aliases  on
extdebug        off
extglob         off
extquote        on
failglob        off
force_fignore   on
globstar        off
gnu_errfmt      off
histappend      on
histreedit      off
histverify      off
hostcomplete    on
huponexit       off
interactive_comments  on
lastpipe        off
lithist         off
login_shell     off
mailwarn        off
no_empty_cmd_completion off
nocaseglob      off
nocasematch     off
nullglob        off
progcomp        on
promptvars      on
restricted_shell  off
shift_verbose   off
sourcepath      on
xpg_echo        off
 



nullglob est sur off... Peut-être à préciser de ma part que ma Wheezy est upgradée de Handy-Linux, ce qui pourrait éventuellement expliquer certaines bizarreries de ma config par défaut !
Tu veux bien m'aider à configurer ça ? smile
Pour le reste... Je vais de lien en lien, j'ai vite fait de me retrouver avc une dizaine d'onglets par fenêtre : c'est pas tout facilement simple smile
Là j'ai 15 jrs de vacances, je vais essayer d'avancer...


Je suis débutant, si à la lecture d'un de mes postes vous avez des suggestions, des liens à me donner ou n'importe quoi qui puisse me faire avancer, n'hésitez pas ! !
Merci smile

Hors ligne

Pied de page des forums