cClaude.rocks ☕ Le blog

[Nouvelles technologies, sciences et coups de gueule…]

Menu

Ce billet est largement inspiré de USEFUL ONE-LINE SCRIPTS FOR SED (Unix stream editor) écrit en 2005.

Je suis tombé par hasard sur cette compilation d’exemples pour sed que je trouve très intéressante, elle est cependant assez ancienne, je vous propose une adaptation libre et modernisée.
Ce document a été traduit, mais la version française n’était pas à jour, je me suis appuyé sur les versions anglaise et française.
L’article de base sépare différentes version de la commande sed, noté que sous les Linux modernes, vous aurez très probablement la version GNU qui est la plus complète.

Attention, cependant sur les Linux embarqués, vous aurez probablement la version BusyBox. À ce jour LibreElec propose la version BusyBox v1.32.1 (2022-03-05 22:56:19 CET) multi-call binary.

Certains exemples sont « overkill », il n’y a pas d’intérêt de remplacer la commande tac par une écriture sed, mais cela peut donner des idées pour traitement spécifique.


ඏ

sed est un éditeur de flux (« fichier ») permettant de filtrer et de transformer un texte. sed est étonnement puissant ; comme la plupart des commandes Unix, il est capable de traiter l’entrée standard, comme un fichier.

À noter, en particulier, que l’option -i, demande à sed d’effectuer les modifications sur les fichiers sur place (« in place ») ; cela permet de modifier de réécrire un fichier. Notez que l’option -i devient ineffective si sed agit sur l’entrée standard.


ඏ

Gestion des lignes (principalement des lignes vides)

  • Traitement sur les lignes
    • Ajoute une ligne vide après chaque ligne :
    sed 'G'
    
    • Ajoute deux lignes vides après chaque ligne :
    sed 'G;G'
    
    • Ajoute une ligne vide lorsqu’il n’y en a pas :

    Plus précisément : on supprime toutes les lignes vides, puis on ajoute une ligne vide après chaque ligne.

    sed '/^$/d;G'
    
    • Efface toutes les lignes paires :

    Efface les lignes, qu’elles soient vides ou non.

    sed 'n;d'
    
    • Insérer une ligne vide au-dessus de chaque ligne qui contient « regex » :
    sed '/regex/{x;p;x;}'
    
    • Insérer une ligne vide sous chaque ligne qui contient l’expression régulière « regex » :
    sed '/regex/G'
    
    • Insérer une ligne vide au-dessus et au-dessous de chaque ligne qui contient « regex » :
    sed '/regex/{x;p;x;G;}'
    

ඏ

Numérotation

  • Numérotation des lignes
    • Numéroter chaque ligne du fichier (appuyé simplement à gauche) :

    L’utilisation d’une tabulation au lieu d’un espace préservera les marges.

    sed '=' nomdefichier | sed 'N;s/\n/\t/'
    
    • Numéroter chaque ligne d’un fichier (numéro à gauche, appuyé à droite) :
    sed '=' nomdefichier | sed 'N; s/^/     /; s/ *\(.\{6,\}\)\n/\1  /'
    
    • Numéroter chaque ligne d’un fichier, mais n’afficher le numéro de ligne que si la ligne n’est pas vide :
    sed '/./=' nomdefichier | sed '/./N; s/\n/ /'
    
    • Compter les lignes (émulation de wc -l) :
    sed -n '$='
    

ඏ

Conversion et substitution de texte

  • Conversion et substitution
    • Environnement UNIX : Conversion des retours de chariot (CR/LF) au format Unix :
    sed 's/.$//'        # assume que toutes les lignes se terminent avec CR/LF
    sed 's/^M$//'       # sous bash/tcsh, utiliser `« CTRL »`+`V` puis `« CTRL »`+`M`
    sed 's/\x0D$//'     # fonctionne sous ssed, gsed 3.02.80 ou plus récent
    
    • Environnement UNIX : Conversion des retours de chariot UNIX (LF) au format DOS :
    sed "s/$/`echo -e \\\r`/"   # ligne de commande sous ksh
    sed 's/$'"/`echo \\\r`/"    # ligne de commande sous bash
    sed "s/$/`echo \\\r`/"      # ligne de commande sous zsh
    sed 's/$/\r/'               # gsed 3.02.80 ou plus récent
    
    • Environnement DOS : Conversion des retours de chariot Unix (LF) au format DOS :
    sed "s/$//"     # méthode 1
    sed -n "p"      # méthode 2
    
    • Environnement DOS : convertir les retours de chariot DOS (CR/LF) au format Unix :
    sed "s/\r//" infile >outfile         # UnxUtils sed v4.0.7 ou plus récent
    tr -d \r <infile >outfile            # GNU tr version 1.22 ou plus récent
    
    • Éliminer tout espace blanc (espaces, tabulations) à la gauche de chaque ligne, et appuyer le résultat à la marge gauche :
    sed 's/^[ \t]*//'
    sed 's/^[[:blank:]]*//'
    
    • Éliminer tout espace blanc (espaces, tabulations) à la fin de chaque ligne :
    sed 's/[ \t]*$//'
    sed 's/[[:blank:]]*$//'
    
    • Éliminer tout espace blanc aux deux bouts de chaque ligne (« trim ») :
    sed 's/^[ \t]*//;s/[ \t]*$//'
    sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
    
    • Insérer 4 espaces au début de chaque ligne (décalage de page vers la droite) :
    sed 's/^/    /'
    
    • Aligner tout le texte à la droite sur la 79e colonne :
    sed -e ':a' -e 's/^.\{1,78\}$/ &/;ta'  # mettre à 78 plus un espace
    
    • Centrer tout le texte sur le centre de la 79e colonne :

    Dans la première méthode, tout espace au début de la ligne est significatif, et des espaces sont ajoutés à la fin de la ligne.
    Dans la seconde méthode, les espaces précédant les lignes sont ignorés pendant le processus de centrage, et aucun espace n’est ajouté à la fin des lignes.

    sed -e ':a' -e 's/^.\{1,77\}$/ & /;ta'                      # méthode 1
    sed -e ':a' -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/'   # méthode 2
    
    • Substituer (trouver et remplacer) « foo » avec « bar » sur chaque ligne :
    sed 's/foo/bar/'             # replacer seulement la première instance de la ligne
    sed 's/foo/bar/4'            # replacer seulement la quatrième instance de la ligne
    sed 's/foo/bar/g'            # replacer toutes les instances de la ligne
    sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # replacer l’avant-dernier cas
    sed 's/\(.*\)foo/\1bar/'            # replacer seulement le dernier cas
    
    • Substituer « foo » par « bar » SEULEMENT pour les lignes contenant « baz » :
    sed '/baz/s/foo/bar/g'
    
    • Substituer « foo » par « bar » a l’exception des lignes contenant « baz » :
    sed '/baz/!s/foo/bar/g'
    
    • Substituer « scarlet » ou « ruby » ou « puce » par « red » :
    sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g'   # la plupart des seds
    gsed 's/scarlet\|ruby\|puce/red/g'                # GNU sed seulement
    
    • Inverser l’ordre des lignes (émulation de tac) :

    Préférez l’usage de tac à ce code illisible, sauf si vous utiliser ce code comme base pour un traitement particulier.

    sed '1!G;h;$!d'               # méthode 1
    sed -n '1!G;h;$p'             # méthode 2
    
    • Inverser l’ordre de chaque caractère sur une ligne (émulation de rev) :

    Préférez l’usage de rev à ce code illisible, sauf si vous utiliser ce code comme base pour un traitement particulier.

    sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
    
    • Joindre des paires de lignes ensemble côte-à-côte (émulation de paste) :
    sed '$!N;s/\n/ /'
    
    • Si une ligne se termine par une barre oblique inversée, joindre la ligne suivante à la présente :
    sed -e ':a' -e '/\\$/N; s/\\\n//; ta'
    
    • Si une ligne débute par le symbole égalité, l’ajouter à la précédente et remplacer le symbole = par un espace simple :
    sed -e ':a' -e '$!N;s/\n=/ /;ta' -e 'P;D'
    
    • Insérer des virgules aux chaînes numériques, changeant 1234567 en 1,234,567 (format US) :
    gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta'                       # GNU sed
    sed -e ':a' -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta'  # autres seds
    
    • Décimaux et signes négatifs (GNU sed) :
    gsed -r ':a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g;ta'
    
    • Ajouter une ligne blanche à chaque cinq lignes (après lignes 5, 10, 15, 20, etc.) :
    gsed '0~5G'                  # GNU sed seulement
    sed 'n;n;n;n;G;'             # autres seds
    

ඏ

Éffassement sélectif de certaines lignes

  • Écrasement sélectif de lignes
    • Imprime tout le fichier sauf la section coïncidant avec deux expressions régulières :
    sed '/Iowa/,/Montana/d'
    
    • Élimine les lignes consécutives identiques d’un fichier (émulation uniq) :

    La première ligne d’un ensemble de lignes identiques consécutives est retenue, les autres éliminées.

    sed '$!N; /^\(.*\)\n\1$/!P; D'
    
    • Élimine les lignes en duplicata, non-consécutives, d’un fichier :

    Prenez garde de ne pas déborder les limites de la mémoire tampon sinon veuillez utiliser le GNU sed.

    sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
    
    • Éliminer toutes les lignes sauf celles en duplicata (émulation uniq -d) :
    sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'
    
    • Éliminer les dix premières lignes d’un fichier :
    sed '1,10d'
    
    • Écraser la dernière ligne d’un fichier :
    sed '$d'
    
    • Écraser les deux dernières lignes d’un fichier :
    sed 'N;$!P;$!D;$d'
    
    • Écraser les dix dernières lignes d’un fichier :
    sed -e ':a' -e '$d;N;2,10ba' -e 'P;D'   # méthode 1
    sed -n -e ':a' -e '1,10!{P;N;D;};N;ba'  # méthode 2
    
    • Écraser chaque huitième ligne :
    gsed '0~8d'             # GNU sed seulement
    sed 'n;n;n;n;n;n;n;d;'  # autres seds
    
    • Écraser les lignes coïncidant avec un patron :
    sed '/patron/d'
    
    • Écraser toutes les lignes vides d’un fichier (émulation grep '.') :
    sed '/^$/d'             # méthode 1
    sed '/./!d'             # méthode 2
    
    • Écraser toutes les lignes vides consécutives (sauf la première) :

    Écrase aussi toutes les lignes vides du début et de la fin d’un fichier (émulation cat -s).

    sed '/./,/^$/!d'          # méthode 1, retient 0 ligne vide au début, 1 à la fin
    sed '/^$/N;/\n$/D'        # méthode 2, permet  1 ligne vide au début, 0  à la fin
    
    • Écraser toutes lignes vides CONSÉCUTIVES d'un fichier, sauf les deux premières :
    sed '/^$/N;/\n$/N;//D'
    
    • Écraser toutes les lignes vides au début d’un fichier :
    sed '/./,$!d'
    
    • Écraser toutes les lignes vides de la fin d’un fichier :
    sed -e ':a' -e '/^\n*$/{$d;N;ba' -e '}'  # fonctionne sur tous les seds
    sed -e ':a' -e '/^\n*$/N;/\n$/ba'        # ibid, sauf pour gsed 3.02.*
    
    • Écrase la dernière ligne de chaque paragraphe :
    sed -n '/^$/{p;h;};/./{x;/./p;}'
    

ඏ

Applications spécifiques

  • Applications spécifiques
    • Éliminer les sur-frappes nerf (char, retour) des pages man :

    La commande echo peut nécessiter le modificateur -e si vous utilisez Unix System V ou du shell bash.

    sed "s/.`echo \\\b`//g"    # double guillemets requis dans l’environnement Unix
    sed 's/.^H//g'             # sous bash/tcsh, enfoncer Ctrl-V et ensuite Ctrl-H
    sed 's/.\x08//g'           # expression hexadécimale pour sed 1.5, GNU sed, ssed
    
    • Obtenir l’entête des messages Usenet/courriel :
    sed '/^$/q'                # élimine tout ce qui suit la première ligne vide
    
    • Obtenir le corps des messages Usenet/courriel :
    sed '1,/^$/d'              # élimine tout ce qui précède la première ligne vide
    
    • Obtenir l’entête Sujet, mais élimine la portion initiale Subject: :
    sed '/^Suject: */!d; s///;q'
    
    • Obtenir l’adresse de retour dans l’entête (Fichier *.eml) :
    sed '/^Reply-To:/q; /^From:/h; /./d;g;q'
    
    • Parcourir et isoler l’adresse proprement dite :

    Extirpe l’adresse courriel par elle-même, du script précédent.

    sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//'
    
    • Ajouter un crochet et espace à chaque ligne (citer un message) :
    sed 's/^/> /'
    

    ** Écraser le crochet et espace précédant chaque ligne (enlever la citation du message) :

    sed 's/^> //'
    
    • Écraser la plupart des étiquettes HTML (s’accommode des étiquettes multi-lignes)
    sed -e ':a' -e 's/<[^>]*>//g;/</N;//ba'
    
    • Extraire les parties uuencodées binaires, éliminant les entêtes superflus, de façon à garder seulement la partie uuencodée.

    Les fichiers doivent être passés à sed dans le bon ordre.

    La version 1 peut être passée depuis la ligne de commande ;
    la version 2 peut faire partie d’un script de shell Unix (Modifiée par un script).

    sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode   # version 1
    sed '/^end/,/^begin/d' "$@" | uudecode                    # version 2
    
    • Triage des paragraphes d’un fichier par ordre alphabétique.

    Les paragraphes sont séparés pour des lignes vides. GNU sed utilise \v comme tabulation verticale, ou n’importe lequel caractère unique peut servir.

    sed '/./{H;d;};x;s/\n/={NL}=/g' file | sort | sed '1s/={NL}=//;s/={NL}=/\n/g'
    gsed '/./{H;d};x;y/\n/\v/' file | sort | sed '1s/\v//;y/\v/\n/'
    
    • Compresser en zip chaque fichier « .TXT » individuellement, écrasant le fichier source et assignant le nom du fichier compressé « .ZIP ».

    Au nom de base du fichier source .TXT (sous DOS: le modificateur "dir /b" retourne les noms de base des fichiers tout en majuscules)

    echo @echo off >zipup.bat
    dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat
    

ඏ

Usage typique

  • Usage typique de sed

    sed accepte une ou plusieurs commandes et les applique toutes, de façon séquentielle, à chacune des lignes d’entrée.
    Une fois que toutes les commandes furent exécutées à la première ligne d’entrée, cette ligne est envoyée vers la sortie, une deuxième ligne est lue comme nouvelle entrée, et le cycle se répète.
    Les exemples précédents présument que l’entrée provient de l’entrée standard (ex. la console, normalement ce serait l’entrée dans un pipeline |). Un ou plusieurs noms de fichiers peuvent être ajoutés à la ligne de commande si l’entrée ne provient pas de l’entrée standard. La sortie est passée à la
    sortie standard (stdout ou l’écran-témoin).

    Donc :

    cat nomdefichier | sed '10q'             # utilise entrée pipeline
    sed '10q' nomdefichier                   # même chose, en moins du cat inutile
    sed '10q' nomdefichier > nouveaufichier  # redirige la sortie vers le disque
    

    Pour des renseignements additionnels sur la syntaxe, incluant comment fournir les instructions sed à partir d’un fichier au lieu de la ligne de commande, veuillez consulter le livre "SED & AWK, 2nd Edition," par Dale Dougherty et Arnold Robbins (O'Reilly, 1997; http://www.ora.com), "UNIX Text Processing," par Dale Dougherty and Tim O'Reilly (Hayden Books, 1987) ou les tutoriels par Mike Arst distribués dans U-SEDIT2.ZIP (plusieurs sites).

    Afin d’exploiter la pleine puissance de sed, l’usager doit comprendre les « expressions régulières ». À cette fin, consultez "Mastering Regular Expressions" par Jeffrey Friedl (O'Reilly, 1997).

    Le manuel UNIX (man) contient des pages qui pourraient être utiles (man sed, man regexp, ou la sous-section sur les expressions régulières (man ed), quoique les pages man sont notoires pour leurs difficultés. Elles ne furent pas rédigées pour enseigner l’usage de sed ou des expressions régulières, mais comme texte de référence pour ceux qui connaissent déjà ces outils.

    SYNTAXE DE CITATION:

    Les exemples précédents utilisent les guillemets simples ('...') au lieu des guillemets doubles ("...") pour encadrer ou citer les commandes d'édition, puisque sed est
    typiquement utilisé sur les systèmes d'exploitation UNIX.

    Les guillemets simples préviennent le shell UNIX d'interpréter les symbole dollar ($) ainsi que les guillemets renversés (...) qui seraient interprétés par le shell s'ils seraient encadrés ou cités par les guillemets doubles.
    Les usagers du shell "csh" et dérivés doivent aussi citer le point d'exclamation avec l'oblique arrière (!) si l'on veut que les exemples ci-haut fonctionnent, même avec à l'intérieur de guillemets simples. Les versions de sed écrites pour DOS invariablement requièrent des guillemets doubles ("...") au lieu des guillemets simples utilisés pour citer les commandes d'édition sed.


ඏ

L’usage de '\t' dans les scripts « sed »

  • Les tabulations

    Afin de clarifier la documentation, nous avons utilisé l’expression '\t' pour indiquer le caractère de tabulation (0x09) dans les scripts.

    Cependant, la plupart des versions de sed ne reconnaissent pas l'abréviation '\t', donc, lorsque vous écrirez ces directives à l'invite de commande, vous devrez enfoncer la clef TAB au lieu de l'abréviation. '\t' est supporté comme métacharactère d'expression régulière dans awk, perl, et HHsed, sedmod, et GNU sed v3.02.80.


ඏ

Versions de sed

Les versions de sed diffèrent entre elles, et de légers écarts de syntaxe se présentent.
En particulier, la plupart ne reconnaissent pas l'usage d'étiquettes (:nom) ou ne permettent pas les instructions de branchement (b,t) à l'intérieur des commandes d'édition, sauf à la fin de ces commandes.
Nous avons donc utilisé une syntaxe qui serait portable à la majorité des usagers de divers sed, bien que les versions les plus populaires du GNU sed permettent une syntaxe plus élaborée.
Lorsque les lecteurs verront une longue chaîne de commande telle celle-ci:

sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d

ils seront réjouis de savoir que GNU sed leur permettra de réduire le tout en ceci:

sed '/AAA/b;/BBB/b;/CCC/b;d'    # ou bien encore en ceci:
sed '/AAA\|BBB\|CCC/b;d'

En plus, se rappeler que bien que certaines versions de sed acceptent une commande telle "/one/ s/RE1/RE2/", d'autres ne permettent pas ceci:
"/one/! s/RE1/RE2/", qui contient un espace avant le 's'. Éviter d'enter l'espace lorsque vous entrez la commande.


ඏ

Optimisation pour vitesse d'exécution

Lorsque vous avez besoin de vitesse pour l'exécution de vos scripts (si vos fichiers d'entrée sont volumineux, ou un processeur lent ou un disque dur lent) la substitution sera plus rapide si vous faites un recherche pour la chaîne à être changée avant de faire la substitution "s/.../.../".

Voir:

sed 's/foo/bar/g' nomdefichier          # commande normale de substitution
sed '/foo/ s/foo/bar/g' nomdefichier    # exécution plus rapide
sed '/foo/ s//bar/g' nomdefichier       # raccourci de syntaxe

Si vous devez altérer ou écraser seulement une section d'un fichier et que vous voulez seulement une sortie pour une première partie d'un fichier quelconque, la commande "quit" (q) dans le script réduira considérablement le temps d'exécution pour de gros fichiers.

Donc:

sed -n '45,50p' nomdefichier        # imprimez les lignes nos. 45-50 d'un fichier
sed -n '51q;45,50p' nomdefichier    # ibid, mais bien plus vite

ඏ

Références et liens

ᦿ


ℹ 2006 - 2022 | 🏠 Accueil du domaine | 🏡 Accueil du blog