Le site arthur.bebou.netlib.re - retour accueil
git clone git://bebou.netlib.re/arthur.bebou
Log | Files | Refs |
commit 567abc40b3a719052cb3463ce0c8620e496561c2 parent a87820d6742fb4d396a0d3f15316b47ac2642de1 Auteurice: Arthur Pons <arthur.pons@unistra.fr> Date: Sat, 10 May 2025 13:08:29 +0200 Début du commentaire sur avoid software Diffstat:
A | contents/avoid-software-commentaires/index.sh | | | 260 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 260 insertions(+), 0 deletions(-)
diff --git a/contents/avoid-software-commentaires/index.sh b/contents/avoid-software-commentaires/index.sh @@ -0,0 +1,260 @@ +#! page +title: Un commentaire à propos de \"Avoid Software\" +author: Arthur Pons +description: Avoid software ? Embrace shell scripts +publication: 2025-05-15 + +section: main + +## Introduction + +[Timothée](https://timothee.goguely.com/) a récemment fait un cours avec des +airs de [missing semester](https://missing.csail.mit.edu/) pour parler de JS, +de CLI et de vie professionnelle en tant que graphiste[^1]. A cette occasion là +il a trouvé une ressource parlant de CLI, faite par et pour des graphistes, +nommée [Avoid Software](https://avoidsoftware.sarahgarcin.com/index.html). + +Cet article a pour but d'être une contribution à ce fanzine : + + * en apportant des précisions sur le fonctionnement des scripts + * en proposant des alternatives aux scripts lorsqu' + * ils ne sont pas POSIX + * ils ne fonctionnent pas sur les fichiers contenant des espaces + * garantissant que tout fonctionne sous OpenBSD + * en proposant une partie expliquant comment transformer les commandes en + scripts qui peuvent prendre des arguments + +## Les dépendances + +## Les scripts + +J'aurais tendance à dire qu'étant donné la manière dont ils sont présentés, ce +qui constitue cette partie sont plutôt des *commandes* que des *scripts*. +Habituellement les *scripts* vont être une ou plusieurs commandes inscrites dans +un fichier que l'on éxecute comme une seule commande par la suite. C'est du +détail mais si une section au sujet de la "scriptisation" des commandes devait +être ajoutée ça rendrait les choses plus claires. + +### Convertir des formats d'image + +La commande `mogrify -format formatfinal *.formatàconvertir` a une +particularité qui n'est pas renseignée. Elle va convertir tous les fichier avec +l'extension `.formatàconvertir` dans le dossier courant. Ce comportement repose +sur l'utilisation des "globs" ou "shell patterns". Le caractère `*` veut dire +"n'importe quel caractère autant de fois que nécessaire". Donc +`*.formatàconvertir` veut dire "tous les fichiers se terminant par +`.formatàconvertir`. On peut penser les globs comme des expressions régulières +beaucoup moins puissantes. + +D'autres caractères intéressants : + + * `?` : "n'importe quel caractère une fois" + * `[]` : introduit ce que l'on appelle une "classe de caractère". En écrivant + `[abc]` on dit "une fois le caractère a, b ou c". Il est également possible + d'utiliser le caractère `-` pour décrire une étendue de caractère. `[3-8]` + ou `[d-h]` voudront dire "une fois un entier entre 3 et 8 inclus" et "une + fois une lettre minuscule entre d et h dans l'ordre alphabétique inclus". + * `!` : dans une classe de caractère permet de prendre le complément des + caractères. `[!abc]` veut dire "une fois n'importe quel caractère *sauf* a, + b ou c". + +On peut donc étendre la commande présentée pour lui faire des choses plus +précises et alambiquées comme : + + mogrify -format formatfinal *-[!1][0-9][0-9]-??.formatàconvertir + +convertir tous les fichiers commençant n'importe comment, suivi d'un tiret, +suivi de n'importe quel caractère n'étant pas un `1` suivi de deux entiers suivi +d'un tiret suivi d'exactement deux caractères suivi de `.formatàconvertir`. + +En arrière plan le shell "développe" le glob en le remplaçant par tous les +chemins auxquels il correspond. Si l'on a trois fichiers dans notre dossier +`a.jpg`, `b.jpg` et `machin.jpg` la commande + + ls ?.jpg + +va s'étendre en + + ls a.jpg b.jpg + +avant de s'éxecuter. Il est possible dans certains shell à l'écriture de la +commande d'obtenir un retour des fichiers qui correspondent en appuyant sur la +touche tabulation comme si l'on voulait compléter le glob. Avec ma configuration +de `zsh` le développement se fait carrément en direct dans le prompt. + +Si vous êtes particulièrement alerte ce fonctionnement par réécriture de +commande devrait vous donner envie de tester un truc. Que se passe-t-il si un +le nom d'un fichier commence par `-` ? Admettons qu'il existe un fichier nommé +`-azerty.jpg` et que l'on utilise le glob `*.jpg` en argument de la fonction +`ls` : + + $ ls *.jpg + # devient + $ ls -azerty.jpg + ls : option invalide -- 'z' + +On se retrouve avec une erreur. Et pour cause, la commande a cru que +`-azerty.jpg` est la déclaration d'options de la commande `ls`. C'est d'autant +plus facile de tomber sur cette erreur que le tiret `-` arrive avant la plupart +des autres caractères dans l'ordre alphanumérique. + +Il y a deux manières de se prémunir de cette erreur. La manière la plus +universelle est d'ajouter `./` devant le glob. `./` voulant dire "le dossier +courant" le glob se développera sur exactement les mêmes fichier qu'auparavant +mais les chemins démarreront tous `./` : + + $ ls ./-azerty.jpg + -azerty.jpg + +Il n'y a donc plus d'ambiguité entre les options et les noms des fichiers. Une +deuxième solution est d'ajouter `--` entre les options et les arguments de la +commande : + + $ ls -larth -- *.jpg + # devient + $ ls -larth -- -azerty.jpg + -rw-r--r-- 1 arthur arthur 0 10 mai 11:27 -azerty.jpg + +Ici `--` permet à la commande de savoir que tout ce qu'il suit doit être +interpréter comme des arguments et non pas comme de potentielles options. Bien +que [cette syntaxe soit +POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02) +toutes les commandes ne respectent pas ce principe, en particulier les commandes +qui ne sont pas "de base" sur les systèmes Unix. La première solution est donc +préférable. + +Des alternatives plus robustes de notre commande sont donc dans l'ordre de +préférence : + + mogrify -format formatfinal ./*.formatàconvertir + mogrify -format formatfinal -- *.formatàconvertir + +Bien sûr l'utilisation de ce genre de commande est habituellement personnelle et +faite dans un environnement maitrisé. Si l'on sait exactement comment sont +nommés nos fichiers il n'y a pas besoin de rendre plus robuste ces commandes. Je +propose ces alternatives au cas-où vous vouliez les partager avec des personnes +dont vous ne connaissez pas le nommage des fichiers et pour apprendre des choses +chouettes à propos du shell :) + +### Diffusion d'erreur + +#### Modifier les images par lot + +La commande + + for img in *.jpg; do + convert "$img" -colorspace Gray -dither FloydSteinberg -colors 4 "dither_$img"; + done + +contient la même faiblesse que la précédente. On peut la corriger simplement en +ajoutant `./` avant le caractère `*`. + +Cette commande peut poser un autre problème. Le shell, lorsqu'il développe le +glob mais ne trouve aucun fichier correspondant, va tout de même tenter de +lancer la commande avec le glob littéralement : + + $ ls *.truc + ls: impossible d'accéder à '*.truc': Aucun fichier ou dossier de ce type + $ touch machin.truc + $ ls *.truc + machin.truc + +Donc dans notre commande s'il n'existe aucun fichier se terminant par `.jpg` +dans le dossier courant la commande `convert` va tout de même s'éxecuter une +fois avec `*.jpg` comme comme argument : + + convert "*.jpg" -colorspace Gray -dither FloydSteinberg -colors 4 "dither_*.jpg"; + +Ce qui n'est pas du tout ce que l'on voulait ! Dans le meilleur des cas cela +provoque une erreur un peu étrange à laquelle on s'attendait pas et dans le pire +des cas la commande fait sens pour le shell et opère sur des fichiers que l'on +ne voulait pas toucher. Malheureusement la solution à cela est un peu sale et +consiste à revérifier à l'intérieur de la boucle si `$img` contient le chemin +d'un fichier qui existe vraiment : + + if [ -e "$img" ];then + cmd + fi + +Une version plus robuste et portable serait donc : + + for img in ./*.jpg; do + if [ -e "$img" ];then + convert "$img" -colorspace Gray -dither FloydSteinberg -colors 4 "dither_$img"; + fi + done + +Dans certains shells il est possible de modifier ce comportement. Par exemple +dans bash et zsh : + + shopt -s nullglob # Pour BASH + setopt NULL_GLOB # Pour ZSH + for img in ./*.jpg; do + convert "$img" -colorspace Gray -dither FloydSteinberg -colors 4 "dither_$img"; + done + +Revient au même mais est plus efficace puisque l'on a plus à vérifier +l'existence du fichier à chaque itération de la boucle. + +### Redimensionner les images pour le web + +Même remarques que pour la commande précédente. + +### Seam Carving + +Maintenant que l'on sait ce que sont les globs on comprend pourquoi il faut +"échapper" le caractère `!` avec un `\` : + + convert image.jpg -liquid-rescale 60x100%\! image_reduce.png + +En l'occurence ce n'est pas un souci pour cette commande mais c'est une bonne +idée de le faire de manière générale sans quoi `!` pourrait être interprété +comme un glob et non pas comme un spécificité d'image-magick. + +Je ne sais pas si c'est voulu mais cette commande converti un jpeg en png. +Peut-être est-ce une faute de frappe ? + +### Convertir des fichiers .mov en .mp4 + +RAS + +### Convertir des fichiers m4a en mp3 + +Même remarques au sujet du glob dans la boucle for : + + for f in ./*.m4a + #plutôt que + for f in *.m4a + +le renommage se fait avec la syntaxe `"${f%.m4a}.mp3"`. En shell il est possible +d'invoquer la valeur d'une variable `f` en écrivant `$f` ou `${f}`. La syntaxe +avec les `{}` permet deux choses : + + * coller la valeur de la variable à une chaîne de caractère. En faisant `echo + "$ftruc"` le shell n'aurait pas la capacité de savoir que l'on veut ce qu'il + y a dans la variable `f` suivi de `truc`. Il penserait que l'on veut la + variable `ftruc`. La solution est d'écrire `echo "${f}truc"`. + * le retrait de suffixe et préfixe. `${f%.m4a}` renvoie la valeur de la + variable `f` avec le plus petit suffixe `.m4a` retiré. Autrement dit c'est + un moyen de retirer l'extension `.m4a` d'un nom de fichier. Il existe des + syntaxes similaires pour retirer le plus grand suffixe possible et les + préfixes les plus petits et grands. + +`${f%.m4a}.mp3` est donc un moyen de prendre une variable `$f` dans laquelle on a +par exemple `truc.m4a`, lui retirer sno extension pour avoir `truc` et y ajouter +une nouvelle extension `.mp3` pour obtenir `truc.mp3` en fin de course. + +### Supprimer les espaces dans les noms de fichier + +La commande `for f in *\ *; do mv "$f" "${f// /_}";` comporte plusieurs erreurs +ou faiblesses. + +Premièrement il manque un `done` à la fin sans quoi on reste dans la boucle +`for` et le nous demande une commande supplémentaire. + +Deuxièmement la désormais habituelle remarque au sujet de la protection contre +les fichiers commençant pas `-`. + +## Au sujet du nom + +[^1]: https://mastodon.design/@timotheegoguely/114478679053770184