Retour Suite
sylvainmahe.site LE SITE de Sylvain Mahé contact@sylvainmahe.site
Article : Sylvain Mahé contact@sylvainmahe.site Création automatique d'un livre à partir d'une arborescence de fichiers Cette routine (pour le système d'exploitation Linux que j'utilise) permet de générer automatiquement un livre complet sous la forme d'un seul fichier, via une arborescence de fichiers (organisation hiérarchique des fichiers dans des répertoires). Face à l'obsolescence progressive, mais bien réelle, des systèmes analogiques et numériques dans le paysage informatique complexe actuel (multitude de technologies matérielles et logicielles plus ou moins hétérogènes), nul ne sait si un matériel de sauvegarde standard considéré de nos jours pourra encore être lu (ouvert en lecture) dans les décennies à venir, et ce malgré le soin apporté à la propagation dans le temps des normes de standardisation de l'analogique et du numérique dans leur ensemble.

Le support imprimé comme le papier relié sous la forme d'un livre peut, dans de bonnes conditions de conservation, rester lisible après plusieurs siècles, voir millénaires. Contrairement aux mémoires non volatiles analogiques ou numériques qui peuvent faire office de supports de sauvegarde (rubans perforés, bandes magnétiques, mémoires à base de semi-conducteurs, etc...), la lecture du papier imprimé s'affranchit d'utiliser un matériel spécifique pour être compréhensible ou décodable, ce qui en fait un candidat relativement pérenne afin d'archiver et de transmettre des informations aux générations futures, en considération de la dépréciation et de l'évolution continue et accélérée respectivement des anciennes et des nouvelles technologies.

C'est pourquoi je pense être utile l'existence de ce présent dispositif que l'on peut qualifier de rudimentaire, particulièrement dans un contexte critique, c'est-à-dire en cas d'obsolescence des techniques informatiques dites modernes sur de longues périodes, ou de crash d'un ou de plusieurs systèmes redondants. Ceci, sans néanmoins être naïf sur la relative fragilité du support imprimé constitué de papier, ainsi que du possible travail laborieux que représente la réintégration du contenu d'un livre dans une machine analogique ou numérique (ce qui semble être une contrainte minimale en proportion de ce que représente la perte définitive d'informations importantes).
Ainsi ce que je propose ici est un outil qui, bien utilisé, vous permettra de sauvegarder vos fichiers sur des supports imprimés (livres, documents divers), via la simple génération d'un seul fichier à texte continu .txt (texte) qu'il convient par la suite de convertir en .pdf (pour "portable document format" ou format de document portable, c'est le format de fichier pris en charge par tous les imprimeurs) à l'aide du programme gedit (le programme gedit conserve à la perfection la pagination du livre). gedit est généralement installé par défaut sur les distributions Linux, mais si vous ne possédez par ce programme (ou paquet), voici la ligne de commande (à écrire dans le terminal) pour l'installer : sudo apt-get install gedit Ma routine d'automatisation prend donc en entrée une arborescence de fichiers, elle permet de choisir les dimensions des pages du livre en nombre de caractères pour la largeur, et en nombre de lignes pour la hauteur (cohérent avec votre conversion en PDF). Si besoin, il est possible également de trier manuellement l'ordre d'apparition des fichiers dans le livre, ce qui peut être intéressant si le tri alphanumérique par défaut n'est pas souhaité. Après quoi un fichier nommé book.txt est créé. Ce fichier répertorie tout le contenu des fichiers de l'arborescence, avec la pagination, la numérotation des lignes, la numérotation des pages (paires et impaires), et la table des fichiers en toute fin du livre. Cette routine (.sh) contient le programme suivant : #!/bin/bash nTable=0 next=false countLineTotal=0 rm book.txt -f echo "Page width (maximum line length) ?" read widthPage echo -e "\nPage height (maximum line number per page) ?" read heightPage echo -e "\nGutter margin (indented text close to the gutter) ?" read marginGutter clear shopt -s globstar for dir in */ do for file in $dir**/* do if [ -f $file ] then fileTable[countTable]=$file ((countTable++)) fi done done while [ $next == false ] do echo "Sort option ?" echo "a = Alphanumeric sort" echo "m = Manual sort" read menuOptionSort if [ $menuOptionSort == "a" ] || [ $menuOptionSort == "m" ] then next=true fi clear done if [ $menuOptionSort == "m" ] then next=false while [ $next == false ] do echo "Manual sort :" echo "e = Exit" echo "s = Save file tree (file.tree)" echo "l = Load file tree (file.tree)" echo "d = Delete file tree (file.tree)" echo "" echo "File tree :" for ((n=0; n < countTable; n++)) do if [ $n == $nTable ] then echo $(($n+1))" = "${fileTable[n]}" <" else echo $(($n+1))" = "${fileTable[n]} fi done read menuManualSort if [ $menuManualSort == "e" ] then next=true elif [ $menuManualSort == "s" ] then rm file.tree -f for ((n=0; n < countTable; n++)) do echo ${fileTable[n]} >> file.tree done elif [ $menuManualSort == "l" ] then nLine=0 while read line do fileTable[$nLine]=$line ((nLine++)) done < file.tree elif [ $menuManualSort == "d" ] then rm file.tree -f elif (($menuManualSort >= 1 && $menuManualSort <= $countTable)) then saveTable=${fileTable[$nTable]} fileTable[$nTable]=${fileTable[$((menuManualSort-1))]} fileTable[$((menuManualSort-1))]=$saveTable fi clear if (($nTable == $countTable - 1)) then nTable=0 else ((nTable++)) fi done fi for ((nTable=0; nTable < countTable; nTable++)) do echo ${fileTable[nTable]} echo "Fichier "${fileTable[nTable]}" :" | fold -s -w$widthPage >> tmp3 echo "" >> tmp3 cp ${fileTable[nTable]} tmp2 sed -i tmp2 -e "s/ /BASH_SPACE/g" -e "s/\t/BASH_TABULATION/g" -e "s/*/BASH_STAR/g" countTmpLine=$(wc -l < tmp2) nTmpLine=1 while read line do if (($countTmpLine < 10)) then widthPrefix=4 spacePrefix="BASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACE" fillSpace="" elif (($countTmpLine < 100)) then widthPrefix=5 spacePrefix="BASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACE" if (($nTmpLine < 10)) then fillSpace="BASH_SPACE" else fillSpace="" fi elif (($countTmpLine < 1000)) then widthPrefix=6 spacePrefix="BASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACE" if (($nTmpLine < 10)) then fillSpace="BASH_SPACEBASH_SPACE" elif (($nTmpLine < 100)) then fillSpace="BASH_SPACE" else fillSpace="" fi elif (($countTmpLine < 10000)) then widthPrefix=7 spacePrefix="BASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACE" if (($nTmpLine < 10)) then fillSpace="BASH_SPACEBASH_SPACEBASH_SPACE" elif (($nTmpLine < 100)) then fillSpace="BASH_SPACEBASH_SPACE" elif (($nTmpLine < 1000)) then fillSpace="BASH_SPACE" else fillSpace="" fi elif (($countTmpLine < 100000)) then widthPrefix=8 spacePrefix="BASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACE" if (($nTmpLine < 10)) then fillSpace="BASH_SPACEBASH_SPACEBASH_SPACEBASH_SPACE" elif (($nTmpLine < 100)) then fillSpace="BASH_SPACEBASH_SPACEBASH_SPACE" elif (($nTmpLine < 1000)) then fillSpace="BASH_SPACEBASH_SPACE" elif (($nTmpLine < 10000)) then fillSpace="BASH_SPACE" else fillSpace="" fi fi echo $line | sed -e "s/BASH_SPACE/ /g" -e "s/BASH_TABULATION/ /g" -e "s/BASH_STAR/*/g" | fold -s -w$((widthPage-widthPrefix)) | sed -e "s/ /BASH_SPACE/g" -e "s/*/BASH_STAR/g" > tmp1 nTmpSubline=1 while read subline do if [ $nTmpSubline == 1 ] then echo $fillSpace$nTmpLine" : "$subline | sed -e "s/BASH_SPACE/ /g" -e "s/BASH_STAR/*/g" >> tmp3 else echo $spacePrefix$subline | sed -e "s/BASH_SPACE/ /g" -e "s/BASH_STAR/*/g" >> tmp3 fi ((nTmpSubline++)) done < tmp1 ((nTmpLine++)) done < tmp2 rm tmp1 rm tmp2 countLine=$(wc -l < tmp3) nLine=0 fillPage=$((heightPage-2)) for ((n=0; n < countLine - 1; n++)) do if (($nLine == $heightPage - 3)) then fillPage=$((fillPage+(heightPage-2))) nLine=0 else ((nLine++)) fi done for ((n=0; n < fillPage - countLine; n++)) do echo "" >> tmp3 done titlePageTable[nTable]=${fileTable[nTable]} if [ $countLineTotal == 0 ] then numberPageTable[nTable]=1 else numberPageTable[nTable]=$(((countLineTotal/(heightPage-2))+1)) fi countLineTotal=$(wc -l < tmp3) done nLine=0 numberPageContent=1 flipFlop=false echo "" for ((n=0; n < countLineTotal; n++)) do if (($nLine == $heightPage - 1)) then echo "Pagination "$((n+1)) sed -i tmp3 -e "$n i \\\\" if [ $flipFlop == false ] then lenghtNumberPageContent=${#numberPageContent} fillSpace="\ " for ((nCharacter=1; nCharacter < widthPage - lenghtNumberPageContent; nCharacter++)) do fillSpace=$fillSpace"\ " done sed -i tmp3 -e "$((n+1)) i $fillSpace$numberPageContent" flipFlop=true else sed -i tmp3 -e $((n+1))"i"$numberPageContent flipFlop=false fi ((numberPageContent++)) elif [ $nLine == $heightPage ] then nLine=0 fi countLineTotal=$(wc -l < tmp3) ((nLine++)) done if [ $flipFlop == false ] then lenghtNumberPageContent=${#numberPageContent} fillSpace="BASH_SPACE" for ((n=1; n < widthPage - lenghtNumberPageContent; n++)) do fillSpace=$fillSpace"BASH_SPACE" done echo -e "\n"$fillSpace$numberPageContent | sed -e "s/BASH_SPACE/ /g" >> tmp3 else echo -e "\n"$numberPageContent >> tmp3 fi echo "" echo -e "Table des fichiers :\n" >> tmp3 for ((nTable=0; nTable < countTable; nTable++)) do echo "File table "${numberPageTable[nTable]} lenghtTitleNumber=$((${#numberPageTable[nTable]}+${#titlePageTable[nTable]})) nCharacter=0 fillLine=$widthPage for ((nCharacter=0; nCharacter < lenghtTitleNumber - 1; nCharacter++)) do if (($nCharacter == $widthPage - 1)) then fillLine=$((fillLine+widthPage)) nCharacter=0 else ((nCharacter++)) fi done point="." for ((nCharacter=3; nCharacter < fillLine - lenghtTitleNumber; nCharacter++)) do point=$point"." done echo ${titlePageTable[nTable]}" "$point" "${numberPageTable[nTable]} | fold -s -w$widthPage >> tmp3 done countLineTotal=$(wc -l < tmp3) nLine=0 fillPage=$heightPage for ((n=0; n < countLineTotal - 1; n++)) do if (($nLine == $heightPage - 1)) then fillPage=$((fillPage+heightPage)) nLine=0 else ((nLine++)) fi done for ((n=0; n < fillPage - countLineTotal; n++)) do echo "" >> tmp3 done if [ $marginGutter != 0 ] then sed -i tmp3 -e "s/ /BASH_SPACE/g" -e "s/*/BASH_STAR/g" fillSpace="BASH_SPACE" for ((n=1; n < marginGutter; n++)) do fillSpace=$fillSpace"BASH_SPACE" done nLine=0 nLineDisplayed=1 flipFlop=false echo "" while read line do if [ $nLine == $heightPage ] then echo "Pagination "$nLineDisplayed if [ $flipFlop == false ] then flipFlop=true else flipFlop=false fi nLine=0 fi if [ $flipFlop == false ] then echo $fillSpace$line | sed -e "s/BASH_SPACE/ /g" -e "s/BASH_STAR/*/g" >> tmp4 else echo $line | sed -e "s/BASH_SPACE/ /g" -e "s/BASH_STAR/*/g" >> tmp4 fi ((nLine++)) ((nLineDisplayed++)) done < tmp3 cp tmp4 book.txt rm tmp3 rm tmp4 else cp tmp3 book.txt rm tmp3 fi exit 0 Lorsque vous exécutez la routine (.sh), se propose à vous une question "Page width (maximum line length) ?", il vous faut alors renseigner le nombre de caractères souhaités pour la largeur des pages (la police de caractère utilisée doit être à espacement unique) : Par exemple si vous indiquez en largeur de page le nombre 50, vous verrez que le nombre de caractères maximums d'une ligne dans les pages ne dépassera jamais 50, une coupure et un retour à la ligne des phrases trop longues sera effectuée (coupure qui s'effectue entre les mots d'une façon naturelle). Ensuite une autre question "Page height (maximum line number per page) ?" apparaît, il convient cette fois-ci de renseigner le nombre de lignes souhaités pour la hauteur des pages : Si vous indiquez en hauteur de page le nombre 75, le nombre de lignes total sur une page de votre livre ne dépassera jamais 75 (numérotation des pages y compris). Puis, la question "Gutter margin (indented text close to the gutter) ?" est posée, vous devez donc renseigner la largeur de la marge (ou retrait) qu'aura le texte par rapport à la reliure du livre : Si vous indiquez en largeur de marge le nombre 10, le texte au bord de la reliure sera éloigné de celle-ci de 10 caractères (vers la gauche pour les pages impaires et vers la droite pour les pages paires), ce qui facilitera d'autant la lecture et l'ergonomie du livre (indiquez un paramètre égal à 0 si vous ne souhaitez aucune marge). Lorsque vous validez cette troisième question, se propose à vous le choix "Sort option ?". Choisissez "a" (pour "Alphanumeric sort" ou tri alphanumérique) puis validez pour trier automatiquement les fichiers dans l'ordre alphanumérique, ou choisissez "m" (pour "Manual sort" ou tri manuel) pour effectuer vous-même le tri. Si vous avez choisi l'option de tri "m", le menu "Manual sort :" (tri manuel) s'affiche à l'écran suivi de quelques commandes (détaillées ci-dessous), ainsi que l'arborescence des fichiers qui vont être inclus dans le livre, avec successivement le numéro d'apparition des fichiers et le chemin d'accès, c'est à ce moment que vous pouvez modifier l'ordre du tri. Voici ci-dessous le détail des commandes possibles : Détail des commandes du menu "Manual sort :" :
- e (pour "Exit" ou sortie) permet de sortir du menu et commencer la génération du livre.
- s (pour "Save" ou sauvegarde) permet de sauvegarder l'arborescence de fichiers dans un fichier nommé file.tree.
- l (pour "Load" ou chargement) permet de charger le fichier nommé file.tree contenant l'arborescence de fichiers.
- d (pour "Delete" ou suppression) permet de supprimer le fichier nommé file.tree contenant l'arborescence de fichiers.

Utilisez ces options pour sauvegarder l'arborescence avec la commande "s", la modifier en ouvrant manuellement le fichier file.tree avec un éditeur de texte (comme gedit par exemple). Puis rechargez cette arborescence modifiée avec la commande "l", vous verrez les modifications s'afficher dans le menu "File tree :".
Plus bas le menu "File tree :" est affiché, c'est l'arborescence de fichiers : La flèche orientée vers la gauche en suffixe des chemins d'accès aux fichiers indique la position de la destination d'un autre fichier source que vous pouvez choisir de déplacer. Validez pour décaler ce curseur vers une autre destination (c'est-à-dire vers le bas), ou écrivez un nombre, puis validez afin de changer la position dans l'arborescence (l'ordre de tri) du fichier indiqué en source (soit le nombre indiqué) vers la destination (soit le curseur en forme de flèche). Exemple :
- Le curseur est positionné sur le fichier numéro 3, c'est la destination.
- J'indique le numéro 10, c'est la source, puis je valide.
- Le fichier en position 10 (la source) prend la position 3 (la destination), et inversement, le 3 prend la position 10.
Lorsque l'ordre de tri des fichiers correspond à ce que vous souhaitez, indiquez la commande "e" puis validez pour sortir du menu et débuter la génération du livre. La génération du livre commence alors. Elle prend logiquement un temps proportionnel à la complexité de l'arborescence de fichiers utilisée comme source, ainsi que le nombre de lignes et de caractères dans la programmation et l'encodage de chaque fichiers. Une fois la génération du livre terminée, un fichier texte (à texte continu) nommé book.txt est constitué, qui doit être converti en PDF (naturellement aux bonnes dimensions largeur et hauteur) afin d'en apercevoir les différentes pages et la structure de pagination d'une manière cohérente. Vous pourrez par exemple ajouter des pages de titres et de sous-titres à ce fichier, ainsi qu'une préface, etc... (c'est-à-dire tout ce que vous souhaitez voir paraître dans le livre en plus du contenu principal utile), puis compiler le tout en un seul fichier .pdf, pour ensuite l'envoyer à un imprimeur. Libre à vous de faire une utilisation de ce petit programme de génération automatique de livre, lorsque vous aurez besoin de sauvegarder vos fichiers sur un autre support que ceux habituellement utilisés dans le monde du numérique !