Historique des commandes

bash enregistre toutes vos commandes dans le fichier .bash_history de votre répertoire personnel. Plusieurs options et outils vous permettent d’en tirer le maximum.

Voyons d’abord comment le configurer. Quatre variables l’affectent:

HISTFILE: nom du fichier d’historique. Si la variable est vide, alors c’est ~/.bash_history. Si la variable n’est pas définie, alors il n’y aura pas d’historique.

HISTSIZE (ou HISTFILESIZE): définit le nombre de commandes que le fichier peut enregistrer. S’il y en a trop, les plus vieilles sont éliminées.

HISTCONTROL: définit les options:

  • ignoredups: ne pas enregistrer les duplicatas successifs.
  • ignorespace: ne pas enregistrer les commandes qui sont précédées d’une espace.
  • ignoreboth: activer ignoredups et ignorespace

HISTTIMEFORMAT: spécifie le format d’affichage de l’horodatage de la commande. Si le format n’est pas spécifié, l’horodatage n’est pas affiché. La syntaxe de spécification du format est identique à celle de la commande date. Exemple: HISTTIMEFORMAT=’%y/%m/%d %T ‘

Comment spécifier

Il y a au moins 3 façons:

  • interactivement: n’affecte que la fenêtre où la commande sera donnée.
    Exemple: HISTCONTROL=ignoredups
    Non-persistant (perdu après un redémarrage).
  • dans ~/.bashrc: n’affecte qu’un usager
    On peut éditer .bashrc ou faire echo HISTCONTROL=ignoredups >> ~/.bashrc
  • dans /etc/bashrc: affecte tous les usagers
    On peut éditer /etc/bashrc ou faire:
    echo HISTCONTROL=ignoredups >> /etc/bashrc

Comment afficher l’historique

La commande history permet d’afficher l’historique. Chaque ligne contiendra le numéro séquenciel, l’horodatage (si défini) et la commande. La commande history a plusieurs options dont une pour vider l’historique (voir man history).

On peut aussi afficher le contenu du fichier .bash_history mais, à ce moment, il n’y aura pas de numéro séquenciel ou d’horodatage. Il faut aussi noter que les commandes courantes seront ajoutées au fichier seulement lorsque la fenêtre sera fermée.

Comment utiliser l’historique

Il y a plusieurs façons:

  • Les flèches ⬆ et ⬇ permettent d’accéder séquentiellement aux commandes récentes.
  • ctrl-r cmd permet de chercher la plus récente cmd dans l’historique. Un ctrl-r supplémentaire accède à la cmd précédente. Les flèches ⬆ et ⬇ permettent d’obtenir la commande précédente ou suivante. Les fléches ⬅ ou ➡ permettent de sortir de la recherche.
  • La commande fc permet d’afficher ou d’éditer les dernières commandes:
    • fc                 permet d’éditer la dernière commande puis de l’exécuter
    • fc -3 -1     permet d’éditer les 3 dernières commandes puis de les exécuter.
    • fc -l            affiche les 16 dernières commandes
    • fc -l -3 -1 affiche les 3 dernières commandes
    • fc -s  [abc=def] cmd localise la dernière cmd, remplace abc par def partout dans la ligne puis l’exécute.

Cette dernière commande (fc -s) est très utile et plusieurs ont pris l’habitude de lui assigner un alias alias r=’fc -s’ dans .bashrc. Cela permet, par exemple:

cp ab25.txt ab25.org
r ab2=yz6 cp

La deuxième commande effectuera:     cp yz65.txt yz65.org

 

screen

screen n’est pas facile à décrire. En gros, il permet de créer une couche entre le système d’exploitation (le kernel) et une ou plusieurs applications. Il permet d’activer plusieurs applications dans une seule fenêtre d’affichage. Il est souvent utilisé avec les applications textuelles pour les détacher/attacher de leur écran.

En général, screen n’est pas installé par défaut mais il s’installe facilement avec votre gestionnaire de paquets.

Démarrage de screen

Le démarrage est simple:

screen prog

si prog n’est pas spécifié, un shell (bash) sera démarré

Détacher une tâche

Si prog s’exécute et est visible dans la fenêtre screen, on peut les séparer (détacher). La fenêtre gérée par screen se fermera automatiquement. Il y a deux façons:

  • dans la fenêtre de l’application (gérée par screen), presser ^a suivi de d. Le préfixe ^a est requis pour éviter que le d soit traité par l’application.
  • dans une fenêtre bash: screen -d

Reprendre une tâche

Si prog est une application détachée de sa fenêtre screen, on peut la ré-associer avec  l’une des 2 façons suivantes:

  • dans une fenêtre bash: screen -r nom
  • dans une fenêtre screen: ^a r nom

Dans les 2 cas, nom est le nom donné par screen à chacune des applications qu’il gère. Il n’est pas nécessaire de spécifier le nom au complet. Il suffit de spécifier les premiers caractères du nom. Si screen ne gère qu’une seule application, le nom est facultatif. Pour connaitre le nom des applications gérées, on utilise screen -list (dans une fenêtre bash).

Exemple (2 sessions vi dans la même fenêtre):

screen vi abc^ad         #dans la fenêtre viscreen vi xyz^adscreen -listThere are screens on:
     15780.pts-6.local4 (Detached)
     13865.pts-6.local4 (Detached)
2 Sockets in /home/u/tmp.
screen -r 13   # récupérer la session d'édition de abc

Conclusion

screen était populaire à l’époque où il n’y avait pas de gestionnaire de fenêtres. Aujourd’hui, on l’utilise sur des équipements à ressources limitées ou pour éviter d’interrompre une application s’il y a déconnexion de son terminal.

screen peut gérer plusieurs fenêtres. Une application peut être ouverte dans une fenêtre puis réactivée dans une autre. Pour plus de détails: man screen

 

Survivre à une déconnexion

Lorsqu’on démarre une tâche sur un ordinateur distant, il faut s’assurer que la tâche est terminée avant de rompre la connexion. En effet, le comportement de Linux dans le cas où une communication est rompue est d’envoyer un signal SIGHUP aux programmes qui dépendent de cette connexion. Si rien n’a été fait pour le contrer, le comportement par défaut est d’arrêter brusquement la tâche.

Déléguer une tâche longue à une autre machine est courant dans le monde Unix/Linux. Mais il faut prendre certaines précautions pour éviter que notre tâche qui s’exécute sur le serveur ne soit avortée par le fait qu’on déconnecte notre portable pour l’amener à la maison.

Vérifions comment notre appli réagit à un signal SIGHUP:

kill -SIGHUP $(pidof appli)

ou

pkill -SIGHUP appli

Si l’application avorte et que ce comportement ne nous convient pas, on pourra utiliser l’une des approches suivantes:

Ajouter le traitement du SIGHUP à notre application

S’il s’agit d’un programme qu’on a écrit ou d’un logiciel libre dont on a le code source, il est facile d’ajouter du code pour traiter le signal SIGHUP.

Demander à bash d’ignorer le signal

Si la solution précédente n’est pas possible, on peut demander à bash d’ignorer le signal SIGHUP:

trap '' SIGHUP
./appli args
trap SIGHUP    # reprendre le comportement par défaut

Exemple d’un script qui ignore les SIGHUP (pour la durée du script):

trap '' SIGHUP
./appli args

On peut aussi utiliser le programme nohup qui déconnecte l’appli de ses canaux standards et envoie toute sortie vers le fichier nohup.out

nohup appli args

screen

screen a été conçu pour gérer plusieurs applications pour une même connexion. Un effet collatéral est que screen créée un lien virtuel entre une application et ses canaux standards (STDIN, STDOUT, STDERR).  Par conséquent, une déconnexion du lien de communication n’est pas perçue par l’application. La tâche continue à s’exécuter en arrière-plan et lorsqu’on rétablit la connexion, on peut refaire le lien avec l’application.

tmux

tmux est semblable à screen et réalise les mêmes fonctions. Sa principale différence est qu’il est de facture plus moderne. tmux se définit comme ‘multiplexeur de terminaux’. Il reprend les concepts de screen mais ajoute un gestionnaire de fenêtre qui partage la fenêtre en zones rectangulaires.

awesome

 

Aide-mémoire: ffmpeg

ffmpeg est un utilitaire de création/gestion/conversion de fichier multi-média. Il s’utilise en ligne de commande et il est particulièrement apprécié pour sa performance et sa souplesse.

ffmpeg dispose d’une kyrielle d’options et, par conséquent, il n’est pas facile à documenter. La lecture de la documentation de ffmpeg est une tâche ardue qui peut même repousser certains débutants.

Le présent article a pour but de montrer que ffmpeg peut être d’utilisation facile. Plutôt que de documenter chacune des options, je vais présenter quelques recettes pré-cuites.

Structure de la ligne de commande

Une commande ffmpeg consiste à spécifier des flux d’entrée et un flux de sortie. On peut spécifier des options pour chacun de ces flux.

ffmpeg reconnait des centaines de formats de fichier. Le format d’un flux d’entrée est généralement auto-détecté mais peut être forcé par l’option -fmt.  Le format du flux de sortie est généralement spécifié par le suffixe du nom de fichier mais peut être forcé par l’option -fmt.

ffmpeg options_globales options_flux_0 -i fichier_flux_0 options_flux_n -i fichier_flux_n] ... options_flux_sortie fichier_flux_sortie

Extraire l’audio d’un flux multi-média (par exemple un film)

ffmpeg -i film.mp4  -q:a 0 -map a musiqueDuFilm.mp3

Cette commande spécifie:

  • le nom du fichier de film (film.mp4)
  • sélection du flux audio (-map a)
  • le nom du fichier de sortie (musiqueDuFilm.mp3)

Convertir un .mp4 pour un vieux lecteur DVD

On vous transmet un documentaire en format .mp4 que vous vous empressez de mettre dans votre lecteur DVD. Le lecteur vous répond que le fichier est incompatible. Pourtant vous avez utilisé ce lecteur plusieurs fois pour lire des .mp4.

Le fichier reçu serait-il corrompu? Oui, peut-être. Mais la cause probable est que l’encodage de votre fichier est trop récent pour que votre lecteur puisse le décoder. Il faut savoir que la norme MP4 a beaucoup évolué au cours des années et il y a donc plusieurs versions de MP4. Ces versions sont principalement justifiées par l’évolution des résolutions et les avancées des algorithmes de compression. La norme H264 (c’est le nom officiel du MP4) est définie en 7 différents profils (profile), chacun ayant près de 20 niveaux (level). Pas évident de s’y retrouver mais le document fr.wikipedia.org/wiki/H.264 peut vous y aider.

Si votre lecteur n’accepte pas plus que High/level3, alors vous pouvez convertir votre document avec:

ffmpeg -i fichier.mp4 -c:a copy -c:v libx264 -profile:v High -level 3 résultat.mp4

Références

 

Aide-mémoire: commandes SED

sed est un éditeur de texte conçu pour automatiser les opérations d’édition des fichiers de texte. Il est principalement utilisé dans des scripts et, par conséquent, il est surtout utilisé par les programmeurs. Il ne faudrait donc pas se surprendre qu’il ne soit ni interactif ni convivial. Les scripts SED sont très performants mais ils deviennent rapidement difficiles à lire. S’ils deviennent trop complexes, il faudrait penser à utiliser un autre outil (AWK, Python, etc). Néanmoins, on le retrouve partout. Parce qu’il est fiable et efficace, il est utilisé partout où les besoins d’édition de texte sont simples mais dépassent les capacités de bash. Il est installé, par défaut, par chacune des distributions.

sed est souvent utilisé avec 1 ou 2 redirections. Si besoin est, vous pouvez rafraichir vos connaissance ici.

Ligne de commande

Parce qu’il n’est pas interactif, les commandes d’édition sont spécifiées sur la ligne de commande ou dans un fichier. Les formes générales de la commande sont:

  • sed  [options] commande fichierTexte
  • sed  [options] -f fichierCommandes fichierTexte

où commande est une commande d’édition (généralement délimitée par des apostrophes ou guillemets).  S’il y a plus d’une commande d’édition, on utilise -e pour chacune des commandes supplémentaires. Le fichier d’entrée est le second paramètre ou une redirection d’entrée. La sortie est le canal 2 (stdout) ou une redirection.

Les options peuvent être:

-e : utiliser un -e pour chaque commande supplémentaire
-f : fichier de commandes-i : envoyer le résultat dans le fichier d'entrée

Trois exemples indépendants:

sed '2d' fichierTexte # effacer la 2ìème ligne du texte
monProg | sed '2d' > fichierSortie
sed -f fichierCommandes fichierTexte > fichierSortie

Syntaxe d’une commande

condition-de-sélection  [!] opération [arguments]

où condition-de-sélection peut être:

la commande s’applique à toutes les lignes
n la commande s’applique à la ligne n seulement.
n,m la commande s’applique aux lignes n à m (inclusivement). Ce type de sélection n’est pas possibles pour les commandes a, i, r, q et =
/exprReg/ la commande s’applique à chacune des lignes où l’expression régulière est vraie
/expr1/, /expr2/ la commande s’applique à chacune des lignes des blocs débutant par expr1 et se terminant par expr2

$ peut être utilisé pour spécifier la dernière ligne.

si la condition  est suivie d’un !, alors la commande ne s’appliquera qu’aux lignes où la condition-de-sélection est fausse.

et l’opération (et ses arguments) peut être:

cmd description options exemples
a insérer ligne vide sous le curseur 1a
d éliminer la ligne du curseur 1d
i insérer ligne vide au-dessus du curseur 1,3i
s remplacer g: répéter
n: nième fois
s/A/B/
s/A/B/g
s/A/B/2
y/// conversion de caractères (un pour un) y/ab/AB/
= afficher numéro de la ligne /proc/=
{ …
… }
grouper plusieurs commandes 1,3{s/A/B/
s/C/D/}

Exemple

Vous décidez de combiner deux sites WEB pour n’en faire qu’un seul. Le 1er site utilisait <H2> pour les titres de pages alors que le second utilisait <H3>. Pour uniformiser,  vous voulez convertir à <H3> tous les <H2> de toutes les pages du 1er site.

for F in *htm
do
  sed -i -e 's/<H2/<H3/g' $F
done

Évidemment, cet exemple ignore le fait qu’il y a aussi des </H qui doivent être convertis. L’oblique étant utilisée comme séparateur par défaut par la commande s, il faudra donc complexifier un peu:

for F in *htm
do
  sed -i -e 's/<\/H2/<\/H3/g' $F
done

Le symbole \ indique à sed que le prochain caractère perd sa signification particulière. Une telle syntaxe peut devenir difficile à lire et il est plus simple de demander à sed de changer son délimiteur (le 1er caractère qui suit la commande s devient le délimiteur).

for F in *htm
do
  sed -i -e 's|</H2|</H3|g' $F
done

La solution finale, avec un peu d’embellissement,  devient:

for F in *htm; do
  sed -i \
    -e 's|<H2|<H3|g' \
    -e 's|</H2|</H3|g' \
    -e 's|<h2|<h3|g' \
    -e 's|</h2|</h3|g' \
    $F
done

 

Unicode et UTF

On ne le croirait pas à priori mais le traitement des caractères par l’ordinateur est devenu un sujet complexe. Pour comprendre, commençons par un peu d’histoire.

Les ordinateurs ne comprennent que les nombres. Pour leur permettre de traiter les caractères, il a fallu associer un nombre à chaque caractère. Il y a eu quelques tentatives (codes de 5 bits, de 7 bits, de 8 bits, de 9 bits, etc). 2 codes ont survécu à cette première époque; ce sont l’ASCII (code de 7 bits) et l’EBCDIC (code de 8 bits, principalement utilisé par IBM). Le texte qui suit ne traitera pas de l’EBCDIC.

N’ayant que 7 bits, l’ASCII ne permet que 128 combinaisons. Il inclut 32 codes de contrôle, 52 caractères alphabétiques (majuscules et minuscules), 10 chiffres et des caractères de ponctuation. Étant d’origine états-unienne, ce code ne laissait aucune place aux caractères particuliers des autres langages. C’était frustrant.

Puis vint le PC (circa 1981). IBM  introduit les codepage. Ce sont des codes de 8 bits où les 128 premiers sont ceux de l’ASCII et les 128 autres sont disponibles pour les autres alphabets. Des compromis étaient nécessaires puisque 256 combinaisons ne sont pas suffisantes pour tous les caractères internationaux. Plus d’une centaine de codepage ont été créés, très souvent incompatibles. Par exemple, le é avait la valeur 130 dans le CP437, 233 dans le CP1252 et 142 dans le Mac-Roman de Apple. Il fallait choisir le codepage en fonction de l’ensemble des caractères à utiliser.

C’était la pagaille.

Vers 1978, Xerox proposa de créer un jeu de caractères universel qui portera plus tard le nom d’Unicode. La 1ère version arriva vers 2004 et nous en sommes aujourd’hui à sa 10ième version. Unicode (aussi connu sous le nom de ISO-10646), contient maintenant 136,755 caractères et symboles. Le problème est qu’il faut au moins 3 octets pour représenter autant de combinaisons. C’était trop!

L’UTF fut développé pour compresser Unicode. Le principe fondamental d’UTF est que les caractères les plus communs se représentent avec un seul octet et que les autres caractères sont représentés par 2, 3 ou 4 octets.

Plusieurs versions d UTF ont été développées:

  • UTF-8 utilise 1 à 4 octets
  • UTF-16 utilise 2 ou 4 octets.  (note1)
  • UTF-32 utilise 4 octets

Est-ce qu’Unicode solutionne tous les problèmes. Pas vraiment!

  • Un fichier ou flux UTF peut débuter par une empreinte (BOM) qui identifie quelle version d’UTF est utilisée et l’ordre des octets (big-endian ou little-endian). Malheureusement, cette empreinte n’est pas obligatoire.
  • Microsoft utilise une empreinte qui leur est propre.
  • La majorité des fichiers existants utilisent un codepage qui n’est pas inscrit dans le fichier.

Détecter quel encodage est utilisé dans un fichier n’est pas évident et plusieurs algorithmes ont été développés pour ce faire.  Mais aucun n’est parfait.

Linux fournit quelques outils pour faire ce travail:

  • La commande file identifie les encodages Unicode mais ne peut rien pour les codepage.
file fichier8
fichier8: UTF-8 Unicode text
  • La commande iconv convertit d’un encodage vers un autre (UTF-8 par défaut). Elle retourne une erreur si le fichier contient des caractères qui sont invalides. Plusieurs centaines d’encodages et codepage sont reconnus. Cette approche permet de vérifier une hypothèse mais pas d’identifier l’encodage.
iconv -f utf8 fichier8 > /dev/null ;; echo OUIOUI
if iconv -f utf16 fichier8 >/dev/null 2>&1; then echo OUI; else echo NON; fi
NON
  • Tous les Linux récents utilisent UTF-8 par défaut. La commande grep permet de repérer les textes qui ont des fautes d’encodage UTF-8.
grep -avx  '.*'  fichier

listera toutes les lignes du fichier qui contiennent un encodage invalide en UTF-8.

Note1: S’il y a une empreinte en début de fichier, UTF-16 devient UTF-16BE (big-endian) ou UTF-16LE (little-endian)

Références

Aide-mémoire: commandes VIM

vim est le remplaçant du vénérable vi. Cet éditeur a été conçu à l’époque où il n’y avait ni souris ni touches de fonction (Fn). Il est encore populaire car c’est l’outil qui vous permettra d’être le plus performant dans vos tâches courantes d’édition de texte. Sa principale caractéristiques est que vos doigts restent toujours sur le clavier, pour l’insertion et les commandes.

Pour utiliser vi, il faut savoir que son opération repose sur un mode. Le mode peut être:

  • mode de commande d’édition, navigation,  recherche,  etc)
  • mode d’insertion de texte
  • mode de commande de gestion ( fichier, aide, etc)

Changements de mode

Esc Active le mode de commande. N’a pas d’effet si on n’est pas en mode d’édition
a-i-o-s Active le mode d’édition. Voir les commandes d’insertion dans la section suivante.
: Active le mode de commande de gestion.

Activation du mode d’édition

a Insère du texte après le curseur.
A Insère du texte à la fin de la ligne.
i Insère du texte avant le curseur.
I Insère du texte au début de la ligne.
o Insère une nouvelle ligne sous la ligne courante.
O Insère une nouvelle ligne au dessus de la ligne courante.
s Efface n caractères au curseur et active le mode d’édition.
S Efface n lignes au curseur et active le mode d’édition.

Sauvegarde et sortie

:q Quitter (s’il n’y a aucun changement)
:q! ou :cq ou ZQ Quitter sans sauvegarder.
:w Sauvegarder.
:w Enregistrer sous …
:wq Sauvegarder et quitter.
ZZ Sauvegarder (s’il y a eu changement) et quitter.

Navigation:
le facteur de répétition [n] est optionnel. Par défaut, il vaut 1.

[n]h Déplace le curseur de n caractères vers la gauche.
[n]j Déplace le curseur de n lignes vers le bas.
[n]k Déplace le curseur de n lignes vers le haut.
[n]l Déplace le curseur de n caractères vers la droite.
0 (zéro) Déplace le curseur vers le début de la ligne.
$ Déplace le curseur vers la fin de la ligne.
^ Déplace le curseur vers le 1er caractère non-blanc de la ligne.
[n]w Déplace le curseur vers le début du prochain mot.
[n]W Déplace le curseur vers le début du prochain mot.
La nuance avec w est le séparateur de mots
[n]b Déplace le curseur vers le début du mot précédent.
[n]B Déplace le curseur vers le début du mot précédent.
La nuance avec b est le séparateur de mots
[n]( Déplace le curseur vers le début de la phrase précédente.
[n]) Déplace le curseur vers le début de la phrase suivante.
[n]{ Déplace le curseur vers le début de la phrase précédente.
[n]} Déplace le curseur vers le début de la phrase suivante.
[n]G Déplace le curseur vers la fin du fichier.
[n]gg Déplace le curseur vers le début du fichier.

Effacement de texte: le facteur de répétition [n] est optionnel. Par défaut, il vaut 1.

[n]x Efface le caractère au curseur.
[n]dd Efface n lignes à partir du curseur.
[n]dw Efface n mots suivants.
d0 Efface du début de ligne jusqu’au curseur.
d$ Efface du curseur jusqu’à la fin de ligne.
d( Efface du curseur jusqu’au début de phrase.
d) Efface du curseur jusqu’à la fin de phrase.
dgg Efface du curseur jusqu’au début de fichier.
dG Efface du curseur jusqu’à la fin de fichier.

Recherche et remplacement de texte

/txt Recherche txt vers l’avant.
?txt Recherche txt vers l’arrière.
/ ou n Aller vers l’occurrence suivante.
? ou N Aller vers l’occurrence précédente.
rcar ou r{txt} Remplacer le caractère au curseur par un ou des caractères.
R Remplacer les caractères à partir du curseur, jusqu’en fin de ligne. Terminer par Esc.
:s/txt1/txt2/ Remplacer txt1 par txt2 dans la ligne courante, 1 fois.
:s/t1/t2/opts Remplacer t1 par t2.  opts peut être:
g: toutes les occurrences
c: demander confirmation à chaque remplacement

Copier/coller
Le copier/coller se fait par l’intermédiaire d’un tampon . On peut utiliser plus d’un tampon. Chacune des commandes qui suivent peut être préfixée par « x où x est l’identificateur du tampon. «  » est le tampon par défaut. « + est le tampon-système (utilisé par les autres applications).

[n]yy ou [n]Y Copier n lignes.
[n]yw Copier n mots.
y$ Copier du curseur à la fin de ligne.
p Coller après le curseur.
P Coller avant le curseur.

Opérations sur blocs

v Sélection de caractères. Déplacer le curseur jusqu’à la fin du bloc.
V Sélection de lignes. Déplacer le curseur jusqu’à la fin du bloc.
V Sélection d’une zone rectangulaire. Déplacer le curseur jusqu’à la fin du bloc.
d Effacer le bloc sélectionné.
c Effacer le bloc sélectionné et activer le mode Insertion.
y Copier le bloc sélectionné. Utiliser y ou Y pour coller.
~ Transformer les minuscules en majuscules et vice-versa.
> Indenter vers la droite (introduire des tab).
< Indenter vers la gauche.
!prog Traiter le bloc avec un prog externe (par exemple: sort.

Repères
Très utiles lorsqu’on édite un long fichier.

mx Création du repère x.
`x Aller au repère x.
:marks Lister les repères créés.

Annulation

u Annulation de la dernière commande.
Ctrl+r Reprendre la commande annulée.

Onglets

:tabnew Crée un nouvel onglet
:tabnew f Ouvre le fichier f dans un nouvel onglet
:tabn Active l’onglet suivant
:tabp Active l’onglet précédent
:tabm n Déplace l’onglet courant vers la position n.
Les positions se numérotent à partir de 0
:tabdo cmd Exécute une commande dans chacun des onglets.
Utile pour effectuer un remplacement global.

Préférences
On peut régler les préférences dans vim (ou modifier le fichier ~/.viminfo).
Les exemples qui suivent ne sont qu’un aperçu. Il y en a trop pour tout couvrir.

:set tabstop=4 Règle la largeur d’indentation.
:set showcmd Affiche la commande incomplète sur la dernière ligne.
:set noshowcmd Désactive la préférence ci-dessus.

Conclusion
La liste des commandes de vim est beaucoup plus exhaustive que ce qui a été montré ici. Cet aide-mémoire sera utile aux utilisateurs occasionnels de vim.

Références

Liste de mots

Récemment, j’ai eu besoin de trouver une liste de mots, une liste exhaustive de mots en français. Une telle liste peut avoir plusieurs usages comme,  par exemple:

  • jouer au scrabble en solitaire
  • solutionner automatiquement des grilles de mots-croisés
  • etc

Ma recherche sur Internet ne m’a pas permis de trouver un fichier suffisamment complet mais j’ai découvert le programme CeWL qui permet de créer des listes en puisant des mots dans des sites WEB. L’idée est bonne.

CeWL est un logiciel libre écrit en Ruby mais je n’ai aucune connaissance de Ruby. J’ai donc décidé d’utiliser le même concept mais de le réaliser en Python. Mon approche initiale est de puiser tous les mots de Wikipédia en français. Pourquoi Wikipédia? La quantité des textes disponibles est impressionnante et la qualité de leurs textes est excellente (peu d’erreurs orthographiques).

La logique d’un tel programme se résume comme suit:

  1. visiter toutes (ou du moins plusieurs) pages de Wikipédia français.
  2. en extraire tous les mots affichés (ne pas tenir compte des mots HTML)
  3. filtrer pour conserver les mots appropriés au besoin
  4. éliminer les duplicata

La 1ère étape se fait facilement avec l’utilitaire wget et les 3 suivantes se font facilement en Python. Le résultat de la 1ère étape prendrait la forme de:

wget [options] fr.wikipedia.org | monFiltre > listeDeMots.txt

Le principe de wget est d’analyser une page WEB et de suivre tous les liens qu’elle contient. Chacune de ces pages contient aussi des liens qui en contiennent d’autres. En explorant tous ces liens, on réussit à explorer un site WEB en ne spécifiant qu’un seul point d’entrée.

wget -E -e robots=off -nd -r -l6 -w1 fr.wikipedia.org

La 2ième étape est plus complexe. Le fichier reçu est en langage HTML. On ne veut pas extraire des mots de la syntaxe HTML. Il faut donc localiser le texte affiché à l’intérieur du HTML. Ce pourrait être complexe car le HTML n’est pas simple.  Heureusement, Python et le module HTMLParser nous simplifieront la tâche. Il suffit d’utiliser le texte qui se trouve à l’intérieur des balises <body … </body> et à l’extérieur des balises <script … </script> et <a … </a>. Une version simplifiée serait:

class htmlParser( HTMLParser):
   def handle_starttag( self, tag, attr):
       enCours.append( tag)

   def handle_endtag( self, tag):
       for i in range( len(enCours), 0, -1):
          if enCours[i-1] == tag: del enCours[i-1]
 
   def handle_data( self, data):
      if ('body' in enCours) and not (('script' in enCours) or ('a' in enCours)):
         for c in ',.;:/(){}[]|?"%@!$&+=_\t\\': txt2 = txt2.replace( c, ' ') # tous sauf "-\'"
         mots = txt2.split()
         for mot in mots:
             # on met ici certaines exclusions ou contraintes:
             if mot.isnumeric(): continue # on ne veut pas de nombres
             mot = mot.lower(): tout en minuscules

             if not (mot in listeMots):
                 listeMots.append(mot)
                 print( mot)

L’étape 3 dépend des besoins spécifiques. Si on veut des mots pour le Scrabble, on remplacera les lettres accentuées par leur version non-accentuée et on convertira tout en majuscules (ou tout en minuscules).

L’étape 4 est facile à réaliser.

Une version plus complète est disponible ici.

Combien de pages faut-il visiter? La section française de Wikipédia contient près de 2 millions de pages. Faut-il toutes les visiter? Non! ce serait un gaspillage d’électrons libres. Plus on visite des pages moins on découvrira de mots nouveaux.  À partir d’un certain point, il n’y aura plus de nouveauté (du moins, c’est ce que je pensais).

Après 20 000 pages (plus de 3Go de trafic), ma liste s’allonge encore (elle est actuellement de plus de 700 000 mots. Malheureusement, j’avais sous-estimé le nombre de noms propres et de noms scientifiques dans les pages Wikipédia. Ma liste contient donc des milliers de noms de fleurs (en français et en latin), des dizaines de milliers de noms d’individus (tel « Éric » « Lapointe »), des centaines de milliers de noms de lieux (tel « Saint-Jean » « Matha ») et des fautes (telle ciconscriptions). Ma 1ère conclusion est que Wikipédia fournit un contenu trop encyclopédique pour mon besoin. Je referai donc le même exercice avec le contenu d’un ensemble de romans. C’est à suivre.

2ième conclusion: ce qui est simple n’est pas nécessairement performant. Le programme présenté plus haut est simple et même trop simple. Un énoncé du genre « if mot in listeMots » semble inoffensif mais lorsque la liste contient plusieurs centaines de milliers de mots, le temps d’exécution de l’énoncé est non-négligeable et devient un goulot d’étranglement. Il existe des techniques plus performantes et ce fera l’objet d’un article futur.

Redirection

Tous les programmes démarrent avec 3 canaux d’entrée-sorties déjà ouverts. Ce sont:

  • 0 (stdin) : entrée normale, généralement le clavier
  • 1 (stdout): sortie normale, généralement l’écran
  • 2 (stderr): sortie des messages d’erreur, généralement l’écran

bash nous permet de rediriger ces canaux vers les entrée-sorties qui correspondent à nos besoins. Trois caractères spéciaux ( <>| ) sont utilisés. Supposons le programme unProg:

unProg <  fichier   # utiliser un fichier au lieu du clavier
unProg >  fichier   # rediriger la sortie vers un fichier (le vider d'abord)
unProg >> fichier   # rediriger la sortie vers un fichier (ajouter au fichier)
unProg | autreProg  # rediriger la sortie vers un autre programme

Un exemple:

cat fichier | wc -l # afficher le nombre de lignes du fichier

Le programme cat affiche le contenu d’un fichier mais, dans ce cas-ci, sa sortie n’ira pas vers l’écran mais plutôt vers le programme wc -l qui compte le nombre de ligne dans le texte entré. Dans ce cas-ci, l’entrée de wc n’est pas le clavier mais, à cause de la redirection, c’est plutôt la sortie du programme précédent.

La forme générale d’une redirection de fichier est n> ou n< où n est le numéro du canal d’entrée-sortie. Donc:

unProg 2> fichier_erreurs

redirige le canal 2 (les messages d’erreurs) vers un fichier. On aura compris que > (sans numéro de canal) est une abréviation de 1>.

Fusion de flux

La formulation n>&m permet de fusionner le canal n avec le canal m

Donc. la commande unProg > fichierX 2>&1    signifie:

  • envoyer la sortie normale vers fichierX
  • fusionner le canal2 (erreurs) et le canal1 (sortie normale)

Notez que l’évaluation se fait de gauche à droite et que, par conséquent, la commande unProg  2>&1  >fichierX ne dirige pas les messages d’erreur vers fichierX

Autres exemples:

prog 1> fich1 2>fich2 # rediriger les canaux 1 et 2
prog 2> /dev/null     # diriger la sortie d'erreur vers la poubelle

Note: il ne faut pas insérer d’espace entre les caractères de n> ou n>&m

Dans le cas d’une redirection vers un programme, on ne peut pas spécifier les canaux; c’est toujours 1 vers 0 (sortie normale vers l’entrée). Si c’est vraiment nécessaire, il y a, bien sur, une façon de diriger 2 (les erreurs) vers l’entrée:

unProg 3>&1   1>&2   2>&3 | autreProg  # on permute 1 et 2

Aide-mémoire: commandes PDB

La majorité des programmeurs Python utilise le print pour déboguer leurs programmes. C’est simple et efficace. Mais il y a des cas plus pointus qui nécessitent un outil plus puissant. pdb en est un.

pdb est un débogueur python en ligne de commande. Il s’inspire de gdb qui est utilisé par les programmeurs de langages compilés tels C et C++.

Parce qu’on ne l’utilise pas souvent, il est facile d’oublier comment on utilise pdb. Voici donc un résumé des commandes. Les crochets [] indiquent les informations optionnelles et la barre verticale | sépare les alternatives d’un choix.

Commande Description
L [début [, fin | nombre]] Liste les lignes du code source. Sans paramètre additionnel, 11 lignes seront affichées, de part et d’autre de la ligne courante.
Le premier paramètre est le numéro de la première ligne à afficher. Le second paramètre est le numéro de la ligne de fin. Si ce second paramètre est inférieur au premier, il représente alors un nombre de lignes.
LL Liste toutes les lignes de la fonction courante. Si aucune fonction n’est en cours, liste tout le fichier courant.
N Exécute l’énoncé courant. S’il s’agit d’un appel de fonction, exécute la fonction au complet.
S Exécute l’énoncé courant. S’il s’agit d’un appel de fonction, le contexte deviendra celui de la fonction.
R Retourne au contexte précédent.
B Liste les points d’arrêts (breakpoints) actifs.

B [fichier:]ligne [condition]

Insère un point d’arrêt à la ligne spécifiée. Si une condition est spécifiée, le point d’arrêt ne sera effectif que si cette condition est vraie.
CL [numéro] Retire le point d’arrêt dont le numéro est spécifié. Si aucun n’est spécifié, retire tous les points d’arrêt.

Pour utiliser pdb, il suffit de spécifier son nom sur la ligne de commande:

python3 -m pdb monProg.py mesParamètres

On peut aussi lancer pdb si notre programme détecte une condition anormale. Il suffit d’ajouter une ligne à l’endroit désiré:

breakpoint()