dernière modification : 2023

sed

sed (stream editor) est un éditeur de flux. Il agit sur chaque ligne du flux qui le traverse, (au même titre que ed agit sur chaque ligne d’un fichier).

sed workflow

1. Comparaison des fonctionnements de ed et sed

L’éditeur de texte ed :

  1. charge en mémoire un fichier, puis

  2. lit les commandes séquentiellement, et pour chacune d’elles, exécute la commande sur le texte en mémoire.

Alors que sed :

  1. charge les commandes en mémoire, puis

  2. pour chaque ligne du flux qui le traverse, applique séquentiellement toutes les commandes à la ligne.

sed

ed et sed ont donc un fonctionnnement inversé.

1.1. sed est un filtre, pas ed

Comme tout filtre, sed ne stocke pas en mémoire le texte qu’il traite. C’est pourquoi il peut traiter sans problème des données volumineuses. Ce n’est pas le cas de ed (et de la plupart des éditeurs de texte) qui peut signaler un manque de mémoire lorsqu’un fichier est trop gros.

En contre-partie, seule la ligne courante a une réalité pour sed, qui ne connait plus la ligne d’avant (elle est passée, oubliée), ni la ligne d’après (elle n’est pas encore arrivée). Exemple, les commandes pour ed suivantes :

$ ed /etc/services         # édite /etc/services
1,$s/a/A/                  # substitue le 1^er^ a de chaque ligne par A
w /tmp/modif.txt           # écrit dans /tmp/modif.txt

sont équivalentes à :

$ sed 's/a/A/' /etc/services > /tmp/modif.txt

2. Compléments

sed par défaut écrit sur stdout toute ligne lue sur stdin, altérée ou non. L’option -n supprime cette fonctionnalité. Il faut alors utiliser la commandes p (print) pour écrire ce que l’on souhaite :

$ sed 's/a/A/'     # sort les lignes modifiées et non modifiées
$ sed -n 's/a/A/'  # ne sort rien (donc ne sert à rien)
$ sed -n 's/a/A/p' # sort uniquement les lignes modifiées

sed comprend par défaut les regex de base, et l’option -r lui demande de comprendre les regex étendues. Par contre, il ne comprend pas les Perl regex.

Exemples :

# les lignes contenant 'root:'
#   équivalent à : grep 'root:' /etc/passwd
$ sed -n '/root:/p' /etc/passwd

# les n° des lignes contenant 'root:'
#   équivalent à : grep -n 'root:' /etc/passwd
$ sed -n '/root:/=' /etc/passwd

# les lignes telles que le premier champ se retrouve en fin de ligne
#   équivalent à : egrep '^([^:]*):.*\1$' /etc/passwd
$ sed -rn '/^([^:]*):.*\1$/p' /etc/passwd

# les lignes ne contenant pas 'nologin'
#   équivalent à : grep -v nologin /etc/passwd
$ sed '/nologin/d' /etc/passwd

# les lignes 2 à 4
$ sed -n '2,4p' /etc/passwd

# les lignes comprises entre celle qui commence par bin et celle qui commence par shutdown
$ sed -n '/^bin/,/^shutdown/p' /etc/passwd

# sur chaque ligne, la 1ère occurence de 'root' est substituée par 'chef'
$ sed  's/root/chef/' /etc/passwd

# sur chaque ligne, toutes les occurences de 'root' sont substituées par 'chef'
$ sed  's/root/chef/g' /etc/passwd

# ajoute un commentaire en fin de chaque ligne faisant référence au 1er champ
$ sed -r 's/^([^:]*):.*$/& # user: \1/' /etc/passwd

# dans les lignes suivant celle qui commence par mail, substitue les ':' en espace
$ sed '/^mail/,$s/:/ /g' /etc/passwd