SCRIPT BASH : Demande vos commentaires et conseils

EDIT: suite à la lecture du post de agentsteel, j’ai modifié dans le titre et dans mon post: “bash” par “dash”.

=========
Bonjour,

J’aimerai avoir vos conseils concernant le script joint à ce post.

Je n’ai jamais eu de cours de programmation si ce n’est en automatisme sur des API de type TSX47 et autres automates programmables, alors je suppose que je dois beaucoup manquer de respect à POSIX, dash et beaucoup d’autres programmes utilitaires en les utilisant de cette façon, mais j’ai fait ce que j’ai pu avec mes faibles connaissances.

Pour ce script, tout a commencé dans ce fil de discussion dans lequel fran.b a posté quelques scripts qui m’ont motivé dans la rédaction de celui-ci, mais je suis conscient qu’il me faudra beaucoup de travail, de lecture et donc de temps avant de savoir utiliser “sed” correctement, et plus particulièrement les “regex” de base.

J’ai récupéré des informations ici, et rassemblé (en vrac) quelques liens et documents ici et que je consulte régulèrement, mais j’avoue ne pas avoir encore tout bien lu et surtout assimilé.

J’espère que vous voudrez bien me montrer les erreurs que j’ai pu faire et comment les éviter à l’avenir,
et vous remercie d’avance pour vos interventions éclairées par vos expériences.

#!/bin/sh -
#=================================================================================================
#        NOM: isoLive2fr.sh
#
#    SYNTAXE: isoLive2fr <fichier image ISO Live>
#
#        BUT: Remplacer le menu de démarrage par une nouvelle entrée.
#             Cette nouvelle entrée permettra un démarrage directement en français.
#
#  NÉCESSITE: Commande     Version      Paquetage
#             --------     -------      -----------
#             isoinfo      1.1.11       genisoimage
#             GNU dd       8.13         coreutils
#             GNU basename 8.13         coreutils
#             GNU awk      4.0.1        gawk
#             GNU sed      4.2.1        sed
#
#     AUTEUR: MicP (debian-fr)
#
#       DATE: 18/07/2014
#
#    VERSION: 0.04.05
#
#-------------------------------------------------------------------------------------------------
# NOTES: Ce n'est qu'une ébauche de script inspiré par ceux qui ont été postés par fran.b
#         dans le fil de discussion suivant :
# http://www.debian-fr.org/franciser-l-iso-debian-7-5-live-nonfree-moins-de-2-minutes-t48948.html
#
# Ça fonctionne, mais je reviendrai plus tard pour rajouter des contrôles d'erreur, et plus...
#-------------------------------------------------------------------------------------------------
# Projets :
#
# - Ajouter la gestion des listes (tableau) en entrée
#     depuis un "glissé" de nom de dossier, ou sélection multiple depuis l'interface graphique.
# - Adapter le script pour pouvoir modifier directement l'image "ISO Live" déjà "gravée" sur Clef USB.
# - Contrôler si le fichier n'a pas déjà été "francisé".
#---------------------------------------------------------------
# En prévision: (Pour le futur script pour le fichier de config)
# - Rechercher dans l'ISO à Franciser les fichiers des locales et clavier disponibles.
#=================================================================================================

fichImgEn="$1"
#-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Ci dessous, la ligne des paramètres de boot qui sera utilisée par le menu de démarrage par défaut.
#   Ce menu apparaîtra en premier dans la liste avec le nom: "Live Fr" (suivit du type d'architecture de votre machine).
#-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
nvParams="append boot=live config quiet splash lang=fr_FR.UTF-8 locales=fr_FR.UTF-8 keyboard-model=pc105 keyboard-layouts=fr keyboard-variant=latin9 timezone=Europe/Paris utc=yes"
#-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#------------------------------------------------------------
#  Y-a t-il un paramètre sur la ligne de commande du script ?
#------------------------------------------------------------
test -z "${fichImgEn}" &&
  {
    printf "\n\nDonnez le chemin du fichier d'image \"ISO Live debian\" à franciser en paramètre de cette commande.\n\n Comme par exemple:\n\n\t$0 ~/Téléchargements/debian-live-7.5.0-amd64-xfce-desktop.iso\n\n\"$0\" vous remercie.\n\n"
    exit 1
  }

#----------------------------------------------------------------
#  Le paramètre corresponds-t-il à un nom de fichier accessible ?
#----------------------------------------------------------------
test -f "${fichImgEn}" ||
  {
    printf "\n\n\"$0\" n'a pu avoir accès à \"${fichImgEn}\".\n\n\tEst-ce bien un nom de fichier ?\n\n"
    exit 1
  }

#-----------------------------------------------
# Récupérer la taille de bloc utilisé par l'ISO.
#-----------------------------------------------
chBlksSize="Logical block size is:"

isoBlckSiz=$(isoinfo -d -i "${fichImgEn}" | sed -n "/${chBlksSize}/p" | sed 's/.* //')

#--------------------------------------------------------------
# Est-ce bien un fichier d'image ISO de type "DEBIAN LIVE" ?
#   pour le savoir, vérifier la présence du fichier "live.cfg".
#--------------------------------------------------------------
NmFichLive="  live.cfg"

varLiveCfg=$(isoinfo -l -R -i "${fichImgEn}" 2>/dev/null | sed -n "/${NmFichLive}/p" | awk '{print $5, $10}')

#----------------------------------------------------------
# Récupérer la taille et la position du fichier "live.cfg".
#----------------------------------------------------------
ficCFGsize=${varLiveCfg%% *} # récup de ce qui précède l'espace
blckOffset=${varLiveCfg##* } # récup de ce qui suit l'espace
octsOffset=$(( $blckOffset * $isoBlckSiz ))

#---------------------------------------------------
# Si le fichier "live.cfg" n'est pas là,
#   l'annoncer par un message, et quitter le script.
#---------------------------------------------------
test -z "${varLiveCfg}" &&
  {
    printf "\n\"$0\" n'a pas pu trouver de fichier \"${NmFichLive}\" dans le fichier \"${fichImgEn}\".\n\n\tCe fichier n'est peut-être PAS un fichier d'image ISO \"Debian Live\"...\n\n"
    exit 1
  }

#----------------------------------------------------------------
# Préparer le nom pour renommer le fichier ISO une fois francisé.
#   (insertion de "-FR" juste après "live")
#----------------------------------------------------------------
frAins="-FR"
insApres="live"

fichImgFr="${fichImgEn%$insApres*}${insApres}${frAins}${fichImgEn#*$insApres}"

#------------------------------------------------------------
# Créer quelques variables pour la création du menu Francisé.
#------------------------------------------------------------
chLive=" ^Live ("
chLiveFR=" ^Live Fr ("
chMenDef="\tmenu default"
chAppend="\tappend boot="

#--------------------------------------------------------------------
# Créer un nom unique dans le temps pour le fichier temporaire,
# dans un sous-répertoire de "/tmp/" au nom du script et utilisateur.
#--------------------------------------------------------------------
nomRepTmp="$(basename $0)"
nomRepTmp="/tmp/${nomRepTmp%.*}-${USER}"
test -d "${nomRepTmp}" || mkdir "${nomRepTmp}"
fichTmp="${nomRepTmp}/tmp-$(date +%s).dat"

#-----------------------------------------------------------------------------------
# Extraire le contenu du fichier "live.cfg",
#  sélectionner le paragraphe concernant le premier menu,
#  modifier le titre du label, supprimer la ligne des paramètres de boot,
#  puis sauvegarder dans "$fichTmp".
#----------------------------------------------------------------------------------
dd bs=1 count=$ficCFGsize skip=$octsOffset if="${fichImgEn}" 2>/dev/null | \
sed -n "1,/${chAppend}/p" | sed -e "s/${chLive}/${chLiveFR}/" -e "/^${chAppend}/d" > "${fichTmp}"

#--------------------------------------------------
# Ajouter la nouvelle chaîne des paramètres de boot
#  + une ligne vide à la fin du fichier temporaire.
#--------------------------------------------------
printf "\t${nvParams}\n\n" >> "${fichTmp}"

#-------------------------------------------
# Remplacer le contenu du fichier "live.cfg"
#  par des caractères 0x00 sur l'image ISO.
#-------------------------------------------
dd bs=1 count=$ficCFGsize seek=$octsOffset if=/dev/zero of="${fichImgEn}" conv=notrunc,sync 2>/dev/null

#------------------------------------------------
# Copie du nouveau contenu du fichier "live.cfg".
#------------------------------------------------
dd bs=1 seek=$octsOffset if="${fichTmp}" of="${fichImgEn}" conv=notrunc,sync 2>/dev/null

#-----------------------------------------
# Renommer le fichier image ISO avec "FR".
#-----------------------------------------
mv "${fichImgEn}" "${fichImgFr}"

#---------------------------------------------
# Supprimer le sous-répertoire et son contenu:
# le fichier temporaire.
#---------------------------------------------
rm -rf "${nomRepTmp}"

#------------------------------
# Annoncer que tout a été fait.
#------------------------------
printf "\nVoilà voilà! \"${fichImgFr}\" est la version francisée.\n\nSomme MD5 :\n"

#-----------------------------------------------------------
# Calcul de la somme MD5 de la nouvelle image ISO francisée.
#-----------------------------------------------------------
md5sum "${fichImgFr}"
printf "\n\n"

#=================================================================================================

EDIT:
Étant donné ce que je viens de lire ici,
je remplace donc les lignes concernées :

…
varLiveCfg=`isoinfo -l -R -i "${fichImgEn}" 2>/dev/null | sed -n "/${NmFichLive}/p" | awk '{print $5, $10}'`
…
isoBlckSiz=`isoinfo -d -i "${fichImgEn}" | sed -n "/${chBlksSize}/p" | sed 's/.* //'`
…

par :

…
varLiveCfg=$(isoinfo -l -R -i "${fichImgEn}" 2>/dev/null | sed -n "/${NmFichLive}/p" | awk '{print $5, $10}')
…
isoBlckSiz=$(isoinfo -d -i "${fichImgEn}" | sed -n "/${chBlksSize}/p" | sed 's/.* //')
…

===========
Là :

…
#------------------------------------------------------------
#  Y-a t-il un paramètre sur la ligne de commande du script ?
#------------------------------------------------------------
test "$fichImgEn" ||
…

je me demande si je n’aurai pas plutôt du utiliser: [mono]test -z “$fichImgEn”[/mono] ?
et bien sûr changer le [mono]||[/mono] en [mono]&&[/mono]
Je cherche …
Je change donc pour le [mono]test -z “$fichImgEn” &&[/mono].

Salut,

[mono]#!/bin/sh[/mono]

si ton script utilise ce “bang”, alors ce n’est pas bash qui est utilisé, mais dash ( packages.debian.org/wheezy/dash )

dash est plus léger donc moins de fonctionnalités que bash

[mono]man dash[/mono] vivement conseillé :slightly_smiling:

par exemple, pour les tests, tu peux en effet utiliser le builtin [mono]test expression[/mono] ou bien [mono][ expression ][/mono].

et pour la substitution de commandes, les deux formes ( les backticks command et $(commande) ) sont possibles.

N’hésite pas aussi à regarder les scripts d’init pour avoir des exemples
[mono]less /etc/init.d/rc[/mono]

:blush: Effectivement: après m’être efforcé de faire du “dash” (m’inspirant des scripts du fil cité) me voilà en train de parler de “bash” jusque dans le titre de ce post :blush:
Le pire, c’est que c’était surtout au sujet du “dash” que je demandais des conseils.

Merci pour les conseils (que je vais suivre) : je repasserai demain (trop occupé aujourd’hui) voir ce que je peux modifier dans le script en fonction de tes conseils.

J’ai trouvé autre chose d’intéressant à faire pour la création du nom du fichier temporaire:
chaque utilisateur aura son sous-répertoire dans “/tmp”, dans lequel ses propres fichiers temporaires seront créés.

#--------------------------------------------------------------
# Créer un nom unique dans le temps pour un fichier temporaire.
#--------------------------------------------------------------
fichTmp="/tmp/aeffacer-$(date +%s).dat"

devient donc:

#-------------------------------------------------------------------------
# Créer un nom unique dans le temps pour le fichier temporaire,
# dans un sous-répertoire de "/tmp/" au nom du script et de l'utilisateur.
#-------------------------------------------------------------------------
nomRepTmp="$(basename $0)"
nomRepTmp="/tmp/${nomRepTmp%.*}-${USER}"     # là, je me demande si c'est bien correct de définir une variable en fonction d'elle même, 
                                             #  qu'en pensez vous ?
test -d "${nomRepTmp}" || mkdir "${nomRepTmp}"
fichTmp="${nomRepTmp}/tmp-`date +%s`.dat"

Ce qui va donner pour le script “isoLive2fr.sh” utilisé par le compte “michel”,
un fichier temporaire dans son sous-répertoire: [mono]/tmp/isoLive2fr-michel/tmp-1405654136.dat[/mono]

Et bien sûr, la destruction du répertoire est ajoutée en fin de script.

#---------------------------------------------
# Supprimer le sous-répertoire et son contenu:
# le fichier temporaire.
#---------------------------------------------
rm -rf "${nomRepTmp}"

===========
NOTE: Ce script ne pourra fonctionner correctement que si:

  • Le fichier “live.cfg” existe bien dans le système de fichiers du fichier “image ISO” donné en paramètre,
  • La chaîne de caractères “live” existe dans le nom du fichier “image ISO” donné en paramètre,
  • La chaîne de caractères " ^Live (" est présente dans le nom du premier label du menu de démarrage de l’ISO,
  • La chaîne de caractères des options de boot du premier label débute par: “append boot= live config quiet splash”.

Pour l’instant, les “ISO Live” de debian ont toutes ça, mais pour combien de temps encore ?

Alors :slightly_smiling:

Je trouve que ton script a beaucoup trop de commentaires. L’exemple le plus frappant est :

[code]
#---------------------------------------------

Supprimer le sous-répertoire et son contenu:

le fichier temporaire.

#---------------------------------------------
rm -rf “${nomRepTmp}”[/code]
4 lignes de commentaire (dont 2 lignes de lignes !) pour une ligne de script.

Soi tu considère que ton script est/peut/doit être utilisé comme exemple pour apprendre les bases du shell et tu peut t’amuser à expliquer ce qu’est rm et mv, soit non est c’est inutile. Je pencherais pour le second cas généralement les gens connaissent le shell avant de se mettre à écrire des scripts.

Les lignes j’imagine que c’est pour essayer de structurer mais ça rend surtout les choses moins visibles, il y a trop de lignes de commentaires et il devient plus difficile de retrouver les informations intéressantes qui s’y trouvent.

En principe c’est le programme qu’on structure plutôt que les commentaires. Crée des méthodes ça permettra de structurer ton programme et tu aura bien moins besoin de commentaires.

Pour l’utilisation de sh, j’en vois pas bien l’intérêt, ton script n’est pas POSIX quoi qu’il arrive (tu dépend d’outil GNU). Se mettre des contraintes pour la beauté du geste n’est pas bien utile.

Pour la gestion des répertoires le paquet coreutils (dont tu dépend déjà) offre le programme mktemp qui fait ça très bien. AMHA une bonne idée (surtout si tu cherche à être multiutilisateur) serait d’utiliser XDG_RUNTIME_DIR s’il est défini.

Tout d’abord, un grand merci pour le retour.

Tout-à fait d’accord, j’essaie simplement d’expliquer mes intentions à ceux qui vont le lire dans ce forum.
Une fois que j’aurai créé des fonctions (comme je suis en train de le faire ces jours-ci), la très très grande majorité (peut-être même tous) des commentaires vont disparaître. Mais je vais refaire tout ça au plus tôt avec le minimum de commentaires.
Voilà les notes (brut) que j’étais en train de préparer depuis hier soir

Je pense créer plusieurs fonctions et/ou scripts pour cette application:
==================================================================
Fonction qui devra traiter les paramètres de la ligne de commande.
==================================================================
- nom du chemin source (périphérique USB, fichier, FTP, HTTP)
  - si cheminSource=dossier => traitement par liste => fonction à créer pour gestion des listes (cases à cocher etc.)
- nom du chemin fichier de configuration ou par défaut
- option gestion historique
- option création configuration
  - option récup des paramètres clavier etc. sur système hôte
  - option création config clavier
  - option création config locale
  - option création config RTC (utc etc.)
  - options autres paramètres (toram, persistence, etc.)
- option remplacer ou ajouter nouvelle ISO.
- option MD5 SHA etc 
  - avant ut/et après création
    (si avant => lien HTTP ou FTP etc. vers source)
- option test en virtualisation Qemu/Kvm ou VirtalBox => ligne de commande pour test
- option interface utilisateur web ou txt ou graphique.
   - option interface web, local/distant

=============================================================================================================
Fonction qui devra récupérer le contenu du fichier "live.cfg" et l'éffacer en le remplissant d'octets à 0x00:
=============================================================================================================
- récupérer, dans un fichier tampon, le contenu de "live.cfg".
- remplacer, dans le fichier image ISO, tout le contenu du fichier "live.cfg" par des 0x00, 

Paramètres entrés:
- chemin ISO (qui pourra être aussi bien un "ficher image ISO" qu'un "fichier de périphérique d'une Clef USB déjà préparée avec LIVE")
- nom fichier ciblé ("live.cfg").

Sortie:
- contenu du fichier "live.cfg" de l'ISO.

============================================================================
Fonction qui devra tester la présence des programmes necessiares à ce script
============================================================================

========================================================
Fonction qui devra préparer le nouveau contenu du label:
========================================================
- isoler et modifier le premier label dans le fichier tampon.
- ajouter la chaîne des paramètres dans la ligne "append=..." déjà présente.

Paramètres entrés:
- tampon fichier récupéré à modifier

- chaîne à insérer dans le label:
  - chaîne à rechercher qui va précéder l'insertion "^Live "
  - chaîne à rechercher qui va suivre l'insertion "("
  (si pas de chaîne avant et après => remplacement de tout ce qui suit "^")

- la chaîne des paramètres à ajouter + "\n".
  (si la chaîne commence par "append=" => remplacer toute la chaîne)

Sortie:
- nouveau contenu du fichier "live.cfg" modifié.

========================================================
Fonction qui devra recopier dans l'ISO le nouveau label:
========================================================
- recopier, dans le fichier image ISO, dans le contenu du fichier "live.cfg", le nouveau label créé.

Paramètres entrés:
- chemin ISO
- nom fichier
- tampon à écrire

Sortie: rien ou erreur

==========================================================
Fonction qui devra donner la nouvelle somme MD5 ou/et SHA:
==========================================================
Paramètres entrés:
- nom nouvelle image ISO

Sortie: retour de la commande de calcul.

Je manque aussi de beaucoup de vocabulaire, par exemple, tu parles de méthode, et je ne sais pas si ça a à voir avec ce que j’appelle “fonction” dans mes notes, sans être sûr que ce terme convienne vraiment à ce que je compte faire.

============

Effectivement, merci de me le faire remarquer, j’ai tellement pas l’habitude que je ne m’en étais même pas rendu compte.
Et donc je comprends bien que dans ce cas:[quote=“MisterFreez”]Se mettre des contraintes pour la beauté du geste n’est pas bien utile.[/quote]

============

mktemp => quelque chose de nouveau pour moi que je vais me régaler d’étudier. Merci

============

[code]michel@debG53SW:~$ echo $XDG_RUNTIME_DIR

michel@debG53SW:~$ echo $XDG_DATA_HOME

michel@debG53SW:~$ echo $XDG_CONFIG_HOME

michel@debG53SW:~$ echo $XDG_DATA_DIRS
/usr/local/share:/usr/share
michel@debG53SW:~$ echo $XDG_CONFIG_DIRS
/etc/xdg
michel@debG53SW:~$ echo $XDG_CACHE_HOME

michel@debG53SW:~$
[/code]
Qu’est ce que j’aimerai, un jour, finir par trouver un filon de références de ce type, mais fiables: qui durent plus longtemps que le temps d’une version ou deux, et qu’on n’aurai qu’à suivre, ça serait tellement plus facile. Pourtant, freedesktop a fait un travail superbe de ce côté là.
Je comprends bien qu’il faille s’adapter (comme pour le répertoire “/dev” qu’on dans lequel on devait créer à la main (avant l’USB) les noeuds de périphérique dont on avait besoins), mais bon…

==============
En tous cas, :grin: je te remercie beaucoup :grin: de t’être penché sur mon semblant de script, et pour les informations que tu m’apporte, je sais que j’ai encore tout à apprendre, il me faudra encore lire et pratiquer beaucoup pour peut-être un jour arriver à faire quelque chose d’acceptable, et ce semblant de script n’a pas la prétention de servir à autre chose que d’être un bon prétexte pour apprendre.

Je commence par le plus important :

Ton script fonctionne donc il est bien. Il y a un paquet de pro qui transpirent à grosses goute quand tu leur parle de script.

Pour XDG base directory, leur description n’oblige absolument pas à définir ces variables, mais ça permet à un utilisateur de faire :

[code]# XDG_RUNTIME_DIR=dir1 ./script.sh &

XDG_RUNTIME_DIR=dir2 ./script.sh[/code]

Par exemple.

Pour méthode/fonction c’est pareil, en principe une méthode ne renvoi rien mais c’est très rare qu’on fasse la distinction.

Pour ta description des fonctions, c’est probablement très bien (je ne l’ai pas lu, d’ailleurs j’ai pas non plus lu ton script), mais c’est très « modèle en V ». Je préfère généralement écrire le code sans commentaire puis me demander quelle partie n’est pas très lisible et je reprend la partie en question (éventuellement en créant une ou plusieurs fonctions) et ainsi de suite itérativement. On a une amélioration progressive du code. Ensuite c’est l’expérience qui va permettre de savoir plus rapidement comment faire et à quel niveau d’abstraction tu veux te situer.

Étant donné que l’image ISO live va être modifiée par et pour un utilisateur depuis sa machine,
j’ai pensé qu’il serait plus simple d’utiliser les variables de sa machine
plutôt que de proposer des liste de choix, du moins pour renseigner les propositions par défaut.

Voici donc une première ligne de commande qui permettant de récupérer certaines de ces variables :

sed                                      \
 -e '/^$/d'                              \
 -e '/^#/d'                              \
 -e 's/\"//g'                            \
 -e '/=$/d'                              \
 -e '/BACKSPACE/d'                       \
 -e 's/XKBMODEL/keyboard-model/'         \
 -e 's/XKBLAYOUT/keyboard-layouts/'      \
 -e 's/XKBVARIANT/keyboard-variants/'    \
 -e 's/XKBOPTIONS/keyboard-options/'     \
/etc/default/keyboard                  | \
tr '\n' ' '                           && \
echo     "timezone=$(cat /etc/timezone)  \
lang=$LANG locales=$LANG"

Ce qui donne sur ma machine :
[mono]keyboard-model=pc105 keyboard-layouts=fr keyboard-variants=oss timezone=Europe/Paris lang=fr_FR.UTF-8 locales=fr_FR.UTF-8[/mono]

Pour la suite de la ligne “append”, je compte utiliser l’interactivité du script afin de renseigner/modifier quelques variables comme [mono]toram[/mono], [mono]persistence[/mono], [mono]hostname[/mono], etc.

Tout commentaire sur cette ligne de commandes et plus particulièrement sur la partie concernant [mono]sed[/mono] qui pourrait peut-être être mal formulée voire remplacée sera bienvenu.

Merci.

======
Je ne sais pas encore, mais je vais tâcher d’éviter de faire installer des paquetages comme [mono]dialog[/mono] ou [mono]zenity[/mono], car en fait, étant donné que dans le cas de ce script il ne s’agira que de déplacer un curseur avec les touche [mono]TAB[/mono] ou flèches vers les zones de saisies (bien grand mot pour dire “en fin de ligne”), et coloriser un peu le tout, les séquences d’échappement me suffiront.

======
Je continue mes recherches afin de créer par petit bouts les divers éléments qu’il faudra, et je créerai à la fin les fonctions qui rendront plus lisible ce “script”.