Du code, du communisme

Remplacer sed, awk, cut et Perl par Python (= bonheur pour sysadmin)

La force de Perl c’est qu’il permettait de piper des données directement via la ligne de commande pour faire des manipulations rapides.
C’est pour cela que c’était devenu les choix des sysadmins. Parce que jusqu’ici, le choix c’était soit de faire un truc simple en connaissant par coeur la tool box GNU, soit ouvrir un fichier et faire un script.
Python ne permet pas de piper des données directement dans la commande, mais des projets ont vu le jour pour le faire.
Il y a le projet pyp, que l’on doit à Sony Pictures Imageworks qui avait besoin de se simplifier l’automatisation des tâches de build pour ses films.
Et il y a pyped, dont j’avais brièvement parlé ici (article qui mérite d’être mis à jour vu que j’ai remplacé dateutils par arrow).
Les deux étaient sympas, mais avait des syntaxes alambiquées, n’étaient pas compatibles python 3 et manquaient d’imports auto. Cependant, pyped est récemment passé en v1.0, donc stable, et a une toute nouvelle approche de syntaxe qui rend la bestiole super agréable à utiliser.
Présentation.

Stdin, ligne à ligne

L’installation est bateau, c’est du pip :

$ pip install --user pyped

Et derrière, on obtient la commande pyp. Elle s’utilise essentiellement à la suite d’une autre commande. Typiquement :

$ cat /etc/fstab | pyp "un truc"

L’astuce, c’est que « un truc » peut être n’importe quelle expression Python. Généralement une expression qui print() quelque chose.
Or, Pyped met automatiquement à disposition de cette expression deux variables :

  • La ligne en cours, dans la variable x.
  • Le numéro de la ligne en cours, dans la variable i.

L’expression Python est appelée une fois pour chaque ligne.
Par exemple, supposons que j’ai un fichier « fortune.txt » contenant :

bitcoin (btc) : 5
euros (€) : 100
dollars ($) : 80

Si je veut tout mettre en majuscule, je fais :

$ cat fortune.txt | pyp "print(x.upper())"
BITCOIN (BTC) : 5
EUROS (€) : 100
DOLLARS ($) : 80

On peut mettre plusieurs expressions d’affilé. Ainsi, si je veux récupérer la somme et le symbole uniquement :

$ cat fortune.txt | pyp "devise, sign, _, value = x.split()" "sign = sign.strip('()')" "print('%s%s' % (value, sign))"
5btc
100€
80$

Ok, c’est plus long que perl, mais vachement plus facile à écrire et à relire. Et j’utilise un langage que je connais déjà. Et pas besoin de faire un mix incompréhensible de sed, awk et autre cut.
Si j’ai vraiment besoin de lisibilité, je peux même le mettre sur plusieurs lignes :

$ cat fortune.txt | pyp "
devise, sign, _, value = x.split()
sign = sign.strip('()')
print('%s%s' % (value, sign))
"
5btc
100€
80$

Vous aurez noté que j’utilise print() et que je semble ne pas me soucier de l’unicode. C’est parceque pyped fait ça au début du script :

from __future__ import print_function, unicode_literals, division, absolute_imports

Du coup, on est bien en Python 2.7, mais on bénéficie de la division améliorée, de la fonction pour printer, des imports absolus et surtout, de l’unicode partout. D’ailleurs pyped vous transforme x pour que ce soit un objet unicode.
Dans tous les cas, pyped est compatible Python 3.

Tout traiter d’un coup

Parfois, on a besoin d’avoir accès à toutes les lignes, pas juste les lignes une à une. pyped permet cela avec l’option -i. Les variables x et i disparaissent au profit de la variable l, qui contient un itérable sur toutes les lignes.
Par exemple, envie de trier tout ça ?

$ cat fortune.txt | pyp -i "
lignes = (x.split() for x in l)
lignes = sorted((v, s.strip('()')) for d, s, _, v in lignes)
for ligne in lignes: print('%s%s' % ligne)
"
100€
5btc
80$

Moar options

Lisez la doc, car il y a d’autres options du genre éviter que pyped vous strip automatiquement le ligne break, forcer l’encoding, etc.
Parmi les trucs les plus utiles, il y a l’option -b qui permet de lancer un code avant la boucle. Pratique pour importer des trucs genre le module tarfile pour extraire une archive avant d’utiliser son contenu.
Néanmoins la plupart du temps on a rien besoin d’importer car pyped importe déjà automatiquement les modules les plus utiles : maths, datetime, re, json, hashlib, uuid, etc.