GNU/Linux >> Tutoriels Linux >  >> Linux

Gérer le saut de ligne avec les commandes Fold et FMT dans le terminal Linux

Lorsque vous utilisez un traitement de texte, le formatage du texte afin que les lignes tiennent dans l'espace disponible sur l'appareil cible ne devrait pas poser de problème. Mais quand on travaille au terminal, les choses ne sont pas si simples.

Bien sûr, vous pouvez toujours couper les lignes à la main à l'aide de votre éditeur de texte préféré, mais cela est rarement souhaitable et même hors de question pour un traitement automatisé.

Espérons que le POSIX fold utilitaire et GNU/BSD fmt La commande peut vous aider à redistribuer un texte afin que les lignes ne dépassent pas une longueur donnée.

Qu'est-ce qu'une ligne sous Unix, déjà ?

Avant d'entrer dans les détails du fold et fmt commandes, définissons d'abord de quoi nous parlons. Dans un fichier texte, une ligne est constituée d'un nombre arbitraire de caractères, suivis de la séquence spéciale de contrôle de saut de ligne (parfois appelée EOL, pour end-of-line )

Sur les systèmes de type Unix, la séquence de contrôle de fin de ligne est constituée du (un seul et unique) caractère saut de ligne , parfois abrégé LF ou écrit \n suivant une convention héritée du langage C. Au niveau binaire, le caractère de saut de ligne est représenté par un octet contenant le 0a valeur hexadécimale.

Vous pouvez facilement vérifier cela en utilisant le hexdump utilitaire que nous utiliserons beaucoup dans cet article. Cela peut donc être une bonne occasion de vous familiariser avec cet outil. Vous pouvez, par exemple, examiner les vidages hexadécimaux ci-dessous pour trouver combien de caractères de saut de ligne ont été envoyés par chaque commande echo. Une fois que vous pensez avoir la solution, réessayez simplement ces commandes sans le | hexdump -C partie pour voir si vous l'avez deviné correctement.

sh$ echo hello | hexdump -C
00000000  68 65 6c 6c 6f 0a                                 |hello.|
00000006
sh$ echo -n hello | hexdump -C
00000000  68 65 6c 6c 6f                                    |hello|
00000005
sh$ echo -e 'hello\n' | hexdump -C
00000000  68 65 6c 6c 6f 0a 0a                              |hello..|
00000007

Il convient de mentionner à ce stade que différents systèmes d'exploitation peuvent suivre différentes règles concernant la séquence de retour à la ligne. Comme nous l'avons vu ci-dessus, les systèmes d'exploitation de type Unix utilisent le saut de ligne caractère, mais Windows, comme la plupart des protocoles Internet, utilise deux caractères :le retour chariot + saut de ligne paire (CRLF, ou 0d 0a , ou \r\n ). Sur Mac OS "classique" (jusqu'à MacOS 9.2 inclus au début des années 2000), les ordinateurs Apple utilisaient le CR seul comme caractère de nouvelle ligne. D'autres ordinateurs hérités utilisaient également la paire LFCR, ou même des séquences d'octets complètement différentes dans le cas d'anciens systèmes incompatibles avec l'ASCII. Heureusement, ces derniers sont des reliques du passé, et je doute que vous voyiez un ordinateur EBCDIC en service aujourd'hui !

En parlant d'histoire, si vous êtes curieux, l'utilisation des caractères de contrôle "retour chariot" et "saut de ligne" remonte au code Baudot utilisé à l'époque du téléscripteur. Vous avez peut-être vu le téléscripteur décrit dans de vieux films comme une interface avec un ordinateur de la taille d'une pièce. Mais même avant cela, les téléscripteurs étaient utilisés "de manière autonome" pour la communication point à point ou multipoint. À cette époque, un terminal typique ressemblait à une lourde machine à écrire avec un clavier mécanique, du papier et un chariot mobile tenant la tête d'impression. Pour commencer une nouvelle ligne, le chariot doit être ramené à l'extrême gauche, et le papier doit se déplacer vers le haut en faisant tourner la platine (parfois appelée « cylindre »). Ces deux mouvements étaient contrôlés par deux systèmes électromécaniques indépendants, les caractères de commande de saut de ligne et de retour chariot étant directement câblés à ces deux parties de l'appareil. Étant donné que le déplacement du chariot nécessite plus de temps que la rotation du plateau, il était logique d'initier le retour chariot en premier. Séparer les deux fonctions a également eu quelques effets secondaires intéressants, comme permettre la surimpression (en envoyant uniquement le CR) ou la transmission efficace du "double interligne" (un CR + deux LF).

La définition au début de cette section décrit principalement ce qu'est une logique ligne est. La plupart du temps, cependant, cette ligne logique "arbitrairement longue" doit être envoyée sur un réseau physique périphérique comme un écran ou une imprimante, où l'espace disponible est limité. L'affichage de lignes logiques courtes sur un périphérique ayant des lignes physiques plus grandes n'est pas un problème. Il y a simplement un espace inutilisé à droite du texte. Mais que se passe-t-il si vous essayez d'afficher une ligne de texte plus grande que l'espace disponible sur l'appareil ? En fait, il existe deux solutions, chacune avec son lot d'inconvénients :

  1. Tout d'abord, l'appareil peut tronquer les lignes à sa taille physique, cachant ainsi une partie du contenu à l'utilisateur. Certaines imprimantes le font, en particulier les imprimantes stupides (et oui, il existe encore des imprimantes matricielles basiques utilisées aujourd'hui, en particulier dans les environnements difficiles ou sales !)
  2. La deuxième option pour afficher de longues lignes logiques consiste à les diviser en plusieurs lignes physiques. C'est ce qu'on appelle le retour à la ligne car les lignes semblent s'enrouler autour de l'espace disponible, un effet particulièrement visible si vous pouvez redimensionner l'affichage comme lorsque vous travaillez avec un émulateur de terminal.

Ces comportements automatiques sont très utiles, mais il arrive encore que vous souhaitiez couper de longues lignes à une position donnée, quelle que soit la taille physique de l'appareil. Par exemple, cela peut être utile si vous souhaitez que les sauts de ligne se produisent à la même position à la fois sur l'écran et sur l'imprimante. Ou parce que vous souhaitez que votre texte soit utilisé dans une application qui n'effectue pas de retour à la ligne (par exemple, si vous intégrez par programme du texte dans un fichier SVG). Enfin, croyez-le ou non, il existe encore de nombreux protocoles de communication qui imposent une largeur de ligne maximale dans les transmissions, y compris les plus populaires comme IRC et SMTP (si vous avez déjà vu l'erreur 550 Longueur de ligne maximale dépassée, vous savez ce que je suis parler de). Il y a donc de nombreuses occasions où vous devez casser de longues lignes en plus petits morceaux. C'est le travail du fold POSIX commande.

La commande de pliage

Lorsqu'il est utilisé sans aucune option, le fold La commande ajoute des séquences de contrôle de saut de ligne supplémentaires pour s'assurer qu'aucune ligne ne dépassera la limite de 80 caractères. Juste pour que ce soit clair, une ligne contiendra au plus 80 caractères plus la séquence de retour à la ligne.

Si vous avez téléchargé le matériel d'assistance pour cet article, vous pouvez essayer par vous-même :

sh$ fold POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1] is a family of standards spec
ified by the IEEE Computer Society for maintaining compatibility between operati
ng systems. POSIX defines the application programming interface (API), along wit
h command line shells and utility interfaces, for software compatibility with va
riants of Unix and other operating systems.[2][3]

# Using AWK to prefix each line by its length:
sh$ fold POSIX.txt | awk '{ printf("%3d %s\n", length($0), $0) }'
 80 The Portable Operating System Interface (POSIX)[1] is a family of standards spec
 80 ified by the IEEE Computer Society for maintaining compatibility between operati
 80 ng systems. POSIX defines the application programming interface (API), along wit
 80 h command line shells and utility interfaces, for software compatibility with va
 49 riants of Unix and other operating systems.[2][3]
  0
 80 The standards emerged from a project that began circa 1985. Richard Stallman sug
 80 gested the name POSIX to the IEEE instead of former IEEE-IX. The committee found
 71  it more easily pronounceable and memorable, and thus adopted it.[2][4]

Vous pouvez modifier la longueur maximale de la ligne de sortie en utilisant le -w option. Plus intéressant est probablement l'utilisation du -s option pour s'assurer que les lignes se coupent à la limite d'un mot. Comparons le résultat sans et avec le -s option lorsqu'elle est appliquée au deuxième paragraphe de notre exemple de texte :

# Without `-s` option: fold will break lines at the specified position
# Broken lines have exactly the required width
sh$ awk -vRS='' 'NR==2' POSIX.txt |
                        fold -w 30 | awk '{ printf("%3d %s\n", length($0), $0) }'
 30 The standards emerged from a p
 30 roject that began circa 1985.
 30 Richard Stallman suggested the
 30  name POSIX to the IEEE instea
 30 d of former IEEE-IX. The commi
 30 ttee found it more easily pron
 30 ounceable and memorable, and t
 21 hus adopted it.[2][4]

# With `-s` option: fold will break lines at the last space before the specified position
# Broken lines are shorter or equal to the required width
awk -vRS='' 'NR==2' POSIX.txt |
                         fold -s -w 30 | awk '{ printf("%3d %s\n", length($0), $0) }'
 29 The standards emerged from a
 25 project that began circa
 23 1985. Richard Stallman
 28 suggested the name POSIX to
 27 the IEEE instead of former
 29 IEEE-IX. The committee found
 29 it more easily pronounceable
 24 and memorable, and thus
 17 adopted it.[2][4]

Évidemment, si votre texte contient des mots plus longs que la longueur de ligne maximale, la commande fold ne pourra pas respecter les -s drapeau. Dans ce cas, le fold l'utilitaire coupera les mots surdimensionnés à la position maximale, en s'assurant toujours qu'aucune ligne ne dépassera la largeur maximale autorisée.

sh$ echo "It's Supercalifragilisticexpialidocious!" | fold -sw 10
It's
Supercalif
ragilistic
expialidoc
ious!

Caractères multi-octets

Comme la plupart, sinon la totalité, des utilitaires de base, le fold La commande a été conçue à un moment où un caractère équivalait à un octet. Cependant, ce n'est plus le cas dans l'informatique moderne, en particulier avec l'adoption généralisée de l'UTF-8. Quelque chose qui mène à des problèmes malheureux :

# Just in case, check first the relevant locale
# settings are properly defined
debian-9.4$ locale | grep LC_CTYPE
LC_CTYPE="en_US.utf8"

# Everything is OK, unfortunately...
debian-9.4$ echo élève | fold -w2
é
l�
�v
e

Le mot « élève » contient deux lettres accentuées :é (LETTRE MINUSCULE LATINE E AVEC AIGU) et è (LETTRE MINUSCULE LATINE E GRAVE). En utilisant le jeu de caractères UTF-8, ces lettres sont codées en utilisant chacune deux octets (respectivement, c3 a9 et c3 a8 ), au lieu d'un seul octet comme c'est le cas pour les lettres latines non accentuées. Vous pouvez vérifier cela en examinant les octets bruts à l'aide du hexdump utilitaire. Vous devriez pouvoir identifier les séquences d'octets correspondant au é et è personnages. Au fait, vous verrez peut-être aussi dans ce dump notre vieil ami le caractère de saut de ligne dont le code hexadécimal a été mentionné précédemment :

debian-9.4$ echo élève | hexdump -C
00000000  c3 a9 6c c3 a8 76 65 0a                           |..l..ve.|
00000008

Examinons maintenant la sortie produite par la commande fold :

debian-9.4$ echo élève | fold -w2
é
l�
�v
e
debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b

Évidemment, le résultat produit par le fold commande est légèrement plus longue que la chaîne de caractères d'origine à cause des retours à la ligne supplémentaires :respectivement 11 octets de long et 8 octets de long, y compris les retours à la ligne. En parlant de ça, dans la sortie du fold commande, vous avez peut-être vu le saut de ligne (0a ) caractère apparaissant tous les deux octets. Et c'est exactement le problème :la commande fold a coupé des lignes à octet positions, pas à caractère postes. Même si cette rupture se produit au milieu d'un caractère multi-octets ! Inutile de mentionner que la sortie résultante n'est plus un flux d'octets UTF-8 valide, d'où l'utilisation du caractère de remplacement Unicode ( ) par mon terminal comme espace réservé pour les séquences d'octets invalides.

Comme pour la cut commande que j'ai écrit il y a quelques semaines, il s'agit d'une limitation dans l'implémentation GNU du fold utilitaire et cela est clairement en opposition avec les spécifications POSIX qui stipulent explicitement que "Une ligne ne doit pas être interrompue au milieu d'un caractère."

Il apparaît donc que le GNU fold l'implémentation ne traite correctement que les codages de caractères à longueur fixe sur un octet (US-ASCII, Latin1, etc.). Pour contourner le problème, si un jeu de caractères approprié existe, vous pouvez transcoder votre texte en un codage de caractères à un octet avant de le traiter, puis le retranscoder en UTF-8. Cependant, c'est pour le moins fastidieux :

debian-9.4$ echo élève |
      iconv -t latin1 | fold -w 2 |
      iconv -f latin1 | hexdump -C
00000000  c3 a9 6c 0a c3 a8 76 0a  65 0a                    |..l...v.e.|
0000000a
debian-9.4$ echo élève |
         iconv -t latin1 | fold -w 2 |
         iconv -f latin1
él
èv
e

Tout cela étant assez décevant, j'ai décidé de vérifier le comportement d'autres implémentations. Comme c'est souvent le cas, l'implémentation OpenBSD du fold l'utilitaire est bien meilleur à cet égard car il est conforme à POSIX et respectera le LC_CTYPE paramètres régionaux pour gérer correctement les caractères multi-octets :

openbsd-6.3$ locale | grep LC_CTYPE
LC_CTYPE=en_US.UTF-8
openbsd-6.3$ echo élève | fold -w 2            C
él
èv
e
openbsd-6.3$ echo élève | fold -w 2 | hexdump -C
00000000  c3 a9 6c 0a c3 a8 76 0a  65 0a                    |..l...v.e.|
0000000a

Comme vous pouvez le voir, l'implémentation d'OpenBSD coupe correctement les lignes au caractère positions, quel que soit le nombre d'octets nécessaires pour les encoder. Dans la grande majorité des cas d'utilisation, c'est ce que vous voulez. Cependant, si vous avez besoin du comportement hérité (c. ”) :

openbsd-6.3$ echo élève | LC_ALL=C fold -w 2
é
l�
�v
e
openbsd-6.3$ echo élève | LC_ALL=C fold -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b

Enfin, POSIX spécifie le -b flag, qui indique le fold utilitaire pour mesurer la longueur de ligne en octets , mais cela garantit néanmoins des caractères multi-octets (selon le LC_CTYPE actuel paramètres régionaux) pas être brisé.

En guise d'exercice, je vous encourage fortement à prendre le temps nécessaire pour trouver les différences au niveau de l'octet entre le résultat obtenu en changeant la locale actuelle en "C" (ci-dessus) et le résultat obtenu en utilisant le -b drapeau à la place (ci-dessous). Cela peut être subtil. Mais il existe une différence :

openbsd-6.3$ echo élève | fold -b -w 2 | hexdump -C
00000000  c3 a9 0a 6c 0a c3 a8 0a  76 65 0a                 |...l....ve.|
0000000b

Alors, avez-vous trouvé la différence ?

Eh bien, en changeant les paramètres régionaux en "C", le fold l'utilitaire n'a pas pris en compte les séquences multi-octets, car, par définition, lorsque la locale est "C", les outils doivent supposer un caractère est un octet . Ainsi, une nouvelle ligne peut être ajoutée n'importe où, même au milieu d'une séquence d'octets qui le ferait ont été considérés comme des caractères multi-octets dans un autre codage de caractères. C'est exactement ce qui s'est passé lorsque l'outil a produit le c3 0a a8 séquence d'octets :les deux octets c3 a8 sont compris comme un seul caractère quand LC_CTYPE définit le codage des caractères comme étant UTF-8. Mais la même séquence d'octets est vue comme deux caractères dans la locale "C":

# Bytes are bytes. They don't change so
# the byte count is the same whatever is the locale
openbsd-6.3$ printf "%d bytes\n" $(echo -n é | LC_ALL=en_US.UTF-8 wc -c)
2 bytes
openbsd-6.3$ printf "%d bytes\n" $(echo -n é | LC_ALL=C wc -c)
2 bytes

# The interpretation of the bytes may change depending on the encoding
# so the corresponding character count will change
openbsd-6.3$ printf "%d chars\n" $(echo -n é | LC_ALL=en_US.UTF-8 wc -m)
1 chars
openbsd-6.3$ printf "%d chars\n" $(echo -n é | LC_ALL=C wc -m)
2 chars

Par contre, avec le -b option, l'outil doit toujours être compatible avec plusieurs octets. Cette option ne change que la façon dont elle compte les positions , en octets cette fois, plutôt qu'en caractères comme c'est le cas par défaut. Dans ce cas, puisque les séquences multi-octets ne sont pas décomposées, la sortie résultante reste un flux de caractères valide (selon le courant LC_CTYPE paramètres régionaux) :

openbsd-6.3$ echo élève | fold -b -w 2
é
l
è
ve

Vous l'avez vu, plus aucune occurrence du caractère de remplacement Unicode ( ), et nous n'avons perdu aucun caractère significatif dans le processus, au prix de finir cette fois avec des lignes contenant un nombre variable de caractères et un nombre variable d'octets. Enfin, tout l'outil s'assure qu'il n'y a pas plus d'octets par ligne que demandé avec le -w option. Quelque chose que nous pouvons vérifier en utilisant le wc outil :

openbsd-6.3$ echo élève | fold -b -w 2 | while read line; do
>   printf "%3d bytes  %3d chars %s\n" \
>             $(echo -n $line | wc -c) \
>             $(echo -n $line | wc -m) \
>             $line
> done
  2 bytes    1 chars é
  1 bytes    1 chars l
  2 bytes    1 chars è
  2 bytes    2 chars ve

Encore une fois, prenez le temps nécessaire pour étudier l'exemple ci-dessus. Il utilise le printf et wc commandes que je n'ai pas expliquées en détail précédemment. Donc, si les choses ne sont pas assez claires, n'hésitez pas à utiliser la section des commentaires pour demander des explications !

Par curiosité, j'ai coché le -b drapeau sur ma boîte Debian en utilisant le GNU fold implémentation :

debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b
debian-9.4$ echo élève | fold -b -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b

Ne passez pas votre temps à essayer de trouver une différence entre le -b et non--b versions de cet exemple :nous avons vu que l'implémentation GNU fold n'est pas compatible multi-octets, donc les deux résultats sont identiques. Si vous n'êtes pas convaincu de cela, vous pouvez peut-être utiliser le diff -s commande pour laisser votre ordinateur le confirmer. Si vous le faites, veuillez utiliser la section des commentaires pour partager la commande que vous avez utilisée avec les autres lecteurs !

Quoi qu'il en soit, cela signifie-t-il le -b option inutile dans l'implémentation GNU du fold utilitaire? Eh bien, en lisant plus attentivement la documentation GNU Coreutils pour le fold commande, j'ai trouvé le -b l'option ne traite que des caractères spéciaux comme la tabulation ou le retour arrière qui comptent respectivement pour 1~8 (un à huit) ou -1 (moins un) position en mode normal, mais ils comptent toujours pour 1 position en mode octet. Déroutant? Donc, peut-être pourrions-nous prendre un peu de temps pour expliquer cela plus en détail.

Gestion des tabulations et des retours arrière

La plupart des fichiers texte que vous traiterez ne contiennent que des caractères imprimables et des séquences de fin de ligne. Cependant, il peut arriver occasionnellement que certains caractères de contrôle se retrouvent dans vos données. Le caractère de tabulation (\t ) est l'un d'eux. Beaucoup plus rarement, le retour arrière (\b ) peuvent également être rencontrés. Je le mentionne encore ici car, comme son nom l'indique, c'est un caractère de contrôle qui fait que le curseur se déplace d'une position en arrière (vers la gauche), alors que la plupart des autres personnages le font aller vers l'avant (vers la droite).

sh$ echo -e 'tab:[\t] backspace:[\b]'
tab:[    ] backspace:]

Cela peut ne pas être visible dans votre navigateur, je vous encourage donc fortement à tester cela sur votre terminal. Mais les caractères de tabulation (\t ) occupe plusieurs positions sur la sortie. Et le retour arrière ? Il semble y avoir quelque chose d'étrange dans la sortie, n'est-ce pas? Alors ralentissons un peu les choses, en divisant la chaîne de texte en plusieurs parties, et en insérant du sleep entre eux :

# For that to work, type all the commands on the same line
# or using backslashes like here if you split them into
# several (physical) lines:
sh$ echo -ne 'tab:[\t] backspace:['; \
  sleep 1; echo -ne '\b'; \
  sleep 1; echo -n ']'; \
  sleep 1; echo ''

D'ACCORD? Vous l'avez vu cette fois ? Décomposons la séquence des événements :

  1. La première chaîne de caractères est affichée "normalement" jusqu'au deuxième crochet ouvrant. A cause du -n flag, l'echo la commande ne fait pas envoyer un caractère de saut de ligne pour que le curseur reste sur la même ligne.
  2. Premier sommeil.
  3. Un retour arrière est émis, ce qui fait reculer le curseur d'une position. Toujours pas de retour à la ligne, donc le curseur reste sur la même ligne.
  4. Deuxième sommeil.
  5. Le crochet fermant s'affiche, écrasant celui d'ouverture.
  6. Troisième sommeil.
  7. En l'absence du -n option, le dernier echo commande envoie enfin le caractère de nouvelle ligne et le curseur se déplace sur la ligne suivante, où votre invite de shell sera affichée.

Bien sûr, un effet tout aussi cool peut être obtenu en utilisant un retour chariot, si vous vous en souvenez :

sh$ echo -n 'hello'; sleep 1; echo -e '\rgood bye'
good bye

Je suis sûr que vous avez déjà vu un utilitaire de ligne de commande comme curl , wget ou ffmpeg affichant une barre de progression. Ils font leur magie en utilisant une combinaison de \b et/ou \r .

Pour intéressant que la discussion puisse être en soi, le but ici était de comprendre que la manipulation de ces caractères peut être difficile pour le fold utilitaire. Heureusement, la norme POSIX définit les règles :

Le compte actuel de la largeur de ligne doit être décrémenté de un, bien que le compte ne devienne jamais négatif. L'utilitaire de repli ne doit pas insérer de immédiatement avant ou après tout . Le nombre actuel de largeur de ligne doit être mis à zéro. L'utilitaire fold ne doit pas insérer de immédiatement avant ou après tout . Chaque rencontré doit faire avancer le pointeur de position de colonne jusqu'au taquet de tabulation suivant. Les taquets de tabulation doivent être à chaque position de colonne n de sorte que n modulo 8 est égal à 1. _

Tous ces traitements spéciaux sont désactivés lors de l'utilisation du -b option. Dans ce cas, les caractères de contrôle avant tout comptent (correctement) pour un octet et ainsi augmenter le compteur de position d'un et d'un seul, comme n'importe quel autre personnage.

Pour une meilleure compréhension, je vous laisse étudier par vous-même les deux exemples suivants (peut-être en utilisant le hexdump utilitaire). Vous devriez maintenant être en mesure de trouver pourquoi "hello" est devenu "hell" et où se trouve exactement le "i" dans la sortie (tel qu'il est là, même si vous ne pouvez pas le voir !) Comme toujours, si vous avez besoin d'aide , ou simplement si vous souhaitez partager vos découvertes, la section des commentaires vous appartient.

# Why "hello" has become "hell"? where is the "i"?
sh$ echo -e 'hello\rgood bi\bye' | fold -w4
hell
good
 bye

# Why "hello" has become "hell"? where is the "i"?
# Why the second line seems to be made of only two chars instead of 4?
sh$ echo -e 'hello\rgood bi\bye' | fold -bw4
hell
go
od b
ye

Autres limites

Le fold La commande que nous avons étudiée jusqu'à présent a été conçue pour décomposer de longues lignes logiques en lignes physiques plus petites, notamment à des fins de formatage.

Cela signifie qu'il suppose que chaque ligne d'entrée est autonome et peut être interrompue indépendamment des autres lignes. Ce n'est pas toujours le cas, cependant. Par exemple, considérons ce courrier très important que j'ai reçu :

sh$ cat MAIL.txt
Dear friends,

Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.

We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.

Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
offer.

Best Regards
Doris
sh$ awk '{ length>maxlen && (maxlen=length) } END { print maxlen }' MAIL.txt
81

De toute évidence, les lignes étaient déjà brisées à une largeur fixe. Le awk m'a dit que la largeur de ligne maximale ici était de ... 81 caractères - à l'exclusion de la nouvelle séquence de lignes. Oui, c'était suffisamment étrange pour que je l'ai revérifié:en effet, la ligne la plus longue a 80 caractères imprimables plus un espace supplémentaire à la 81e position et seulement après cela, il y a le caractère de saut de ligne. Les informaticiens travaillant pour le compte de ce « fabricant » de chaises pourraient probablement profiter de la lecture de cet article !

Quoi qu'il en soit, en supposant que je souhaite modifier le formatage de cet e-mail, j'aurai des problèmes avec le fold commande à cause des sauts de ligne existants. Je vous laisse vérifier les deux commandes ci-dessous par vous-même si vous le souhaitez, mais aucune d'entre elles ne fonctionnera comme prévu :

sh$ fold -sw 100 MAIL.txt
sh$ fold -sw 60 MAIL.txt

Le premier ne fera tout simplement rien puisque toutes les lignes sont déjà plus courtes que 100 caractères. Concernant la deuxième commande, elle coupera les lignes à la 60e position mais conservera les caractères de saut de ligne déjà existants afin que le résultat soit irrégulier. Il sera particulièrement visible dans le troisième paragraphe :

sh$ awk -v RS='' 'NR==3' MAIL.txt |
            fold -sw 60 |
            awk '{ length>maxlen && (maxlen=length); print length, $0 }'
53 We supply all kinds of wooden, resin and metal event
25 chairs, include chiavari
60 chairs, cross back chairs, folding chairs, napoleon chairs,
20 phoenix chairs, etc.

La première ligne du troisième paragraphe était interrompue à la position 53, ce qui correspond à notre largeur maximale de 60 caractères par ligne. Cependant, la deuxième ligne s'est interrompue à la position 25 car ce caractère de nouvelle ligne était déjà présent dans le fichier d'entrée. En d'autres termes, pour redimensionner correctement les paragraphes, nous devons d'abord rejoindre les lignes avant de les couper à la nouvelle position cible.

Vous pouvez utiliser sed ou awk pour rejoindre les lignes. Et en fait, comme je l'ai mentionné dans la vidéo d'introduction, ce serait un bon défi à relever pour vous. Alors n'hésitez pas à poster votre solution dans la section des commentaires.

Quant à moi, je vais suivre un chemin plus simple en regardant le fmt commande. Bien qu'il ne s'agisse pas d'une commande standard POSIX, elle est disponible à la fois dans le monde GNU et BSD. Il y a donc de bonnes chances qu'il soit utilisable sur votre système. Malheureusement, le manque de standardisation aura des implications négatives comme nous le verrons plus tard. Mais pour l'instant, concentrons-nous sur les bons côtés.

La commande fmt

Le fmt la commande est plus évoluée que le fold commande et a plus d'options de formatage. La partie la plus intéressante est qu'il peut identifier les paragraphes dans le fichier d'entrée en fonction des lignes vides. Cela signifie que toutes les lignes jusqu'à la prochaine ligne vide (ou la fin du fichier) seront d'abord réunies pour former ce que j'ai appelé plus tôt une "ligne logique" du texte. Seulement après cela, le fmt la commande cassera le texte à la position demandée.

Voyons maintenant ce que cela changera lorsqu'il sera appliqué au deuxième paragraphe de mon exemple de courrier :

sh$  awk -v RS='' 'NR==3' MAIL.txt |
             fmt -w 60 |
             awk '{ length>maxlen && (maxlen=length); print length, $0 }'
60 We supply all kinds of wooden, resin and metal event chairs,
59 include chiavari chairs, cross back chairs, folding chairs,
37 napoleon chairs, phoenix chairs, etc.

Pour l'anecdote, le fmt commande acceptée pour emballer un mot de plus dans la première ligne. Mais plus intéressant, la deuxième ligne est maintenant remplie, ce qui signifie que le caractère de saut de ligne déjà présent dans le fichier d'entrée après le mot "chiavari" (qu'est-ce que c'est ?) a été supprimé. Bien sûr, les choses ne sont pas parfaites, et le fmt l'algorithme de détection de paragraphe déclenche parfois des faux positifs, comme dans les salutations à la fin du mail (ligne 14 de la sortie) :

sh$ fmt -w 60 MAIL.txt | cat -n
     1  Dear friends,
     2
     3  Have a nice day!  We are manufactuer for event chairs and
     4  tables, more than 10 years experience.
     5
     6  We supply all kinds of wooden, resin and metal event chairs,
     7  include chiavari chairs, cross back chairs, folding chairs,
     8  napoleon chairs, phoenix chairs, etc.
     9
    10  Our chairs and tables are of high quality and competitively
    11  priced.  If you need our products, welcome to contact me;we
    12  are happy to make you special offer.
    13
    14  Best Regards Doris

J'ai dit plus tôt le fmt La commande était un outil de formatage de texte plus évolué que le fold utilitaire. En effet, ça l'est. Ce n'est peut-être pas évident à première vue, mais si vous regardez attentivement les lignes 10-11, vous remarquerez peut-être qu'il utilise deux espaces après le point - appliquant une convention la plus discutée consistant à utiliser deux espaces à la fin d'une phrase. Je n'entrerai pas dans ce débat pour savoir si vous devez ou non utiliser deux espaces entre les phrases mais vous n'avez pas vraiment le choix ici :à ma connaissance, aucune des implémentations courantes du fmt La commande offre un indicateur pour désactiver le double espace après une phrase. A moins qu'une telle option existe quelque part et que je l'ai raté ? Si tel est le cas, je serai ravie que vous me le fassiez savoir en utilisant la section des commentaires :en tant qu'écrivain français, je n'ai jamais utilisé le « double interligne » après une phrase…

Plus d'options fmt

Le fmt L'utilitaire est conçu avec plus de capacités de formatage que la commande fold. Cependant, n'étant pas défini par POSIX, il existe des incompatibilités majeures entre les options GNU et BSD.

Par exemple, le -c L'option est utilisée dans le monde BSD pour centrer le texte alors que dans fmt de GNU Coreutils il active le mode de marge de couronne, « en préservant l'indentation des deux premières lignes dans un paragraphe, et en alignant la marge gauche de chaque ligne suivante avec celle de la deuxième ligne. "

Je vous laisse expérimenter par vous-même avec le GNU fmt -c si tu veux. Personnellement, je trouve la fonctionnalité de centrage de texte BSD plus intéressante à étudier à cause d'une certaine bizarrerie :en effet, dans OpenBSD, fmt -c centrera le texte en fonction de la largeur cible, mais sans le redistribuer ! So the following command will not work as you might have expected:

openbsd-6.3$ fmt -c -w 60 MAIL.txt
                        Dear friends,

                      Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.

We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.

Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
                           offer.

                        Best Regards
                            Doris

If you really want to reflow the text for a maximum width of 60 characters and center the result, you will have to use two instances of the fmt commande :

openbsd-6.3$ fmt -w 60 MAIL.txt | fmt -c -w60
                        Dear friends,

  Have a nice day!  We are manufactuer for event chairs and
           tables, more than 10 years experience.

We supply all kinds of wooden, resin and metal event chairs,
 include chiavari chairs, cross back chairs, folding chairs,
            napoleon chairs, phoenix chairs, etc.

 Our chairs and tables are of high quality and competitively
 priced.  If you need our products, welcome to contact me;we
            are happy to make you special offer.

                     Best Regards Doris

I will not make here an exhaustive list of the differences between the GNU and BSD fmt implementations … essentially because all the options are different! Except of course the -w option. Speaking of that, I forgot to mention -N where N is an integer is a shortcut for -wN . Moreover you can use that shortcut both with the fold et fmt commands:so, if you were perseverent enough to read his article until this point, as a reward you may now amaze your friends by saving one (!) entire keystroke the next time you will use one of those utilities:

debian-9.4$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified
by the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface

openbsd-6.3$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1]
is a family of standards specified by the IEEE
Computer Society for maintaining compatibility
between operating systems. POSIX defines the
application programming interface (API), along

debian-9.4$ fold -sw50 POSIX.txt  | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface

openbsd-6.3$ fold -sw50 POSIX.txt  | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface

As the final word, you may also notice in that last example the GNU and BSD versions of the fmt utility are using a different formatting algorithm, producing a different result. On the other hand, the simpler fold algorithm produces consistent results between the implementations. All that to say if portability is a premium, you need to stick with the fold command, eventually completed by some other POSIX utilities. But if you need more fancy features and can afford to break compatibility, take a look at the manual for the fmt command specific to your own system. And let us know if you discovered some fun or creative usage for those vendor-specific options!


Linux
  1. Comment utiliser les commandes 'cat' et 'tac' avec des exemples sous Linux

  2. Partage de sessions de terminal Linux avec Tmux et Screen

  3. Commandes tête et queue sous Linux expliquées avec des exemples

  4. Top 5 des commandes intéressantes et amusantes sur Linux (Fun Terminal)

  5. Linux - Comment synchroniser deux dossiers avec des outils de ligne de commande ?

Mon terminal Linux riche en fonctionnalités et minimal

Personnalisation de mon terminal Linux avec tmux et Git

Puissances de deux, puissances de Linux :2048 en ligne de commande

Comment travailler avec le processus de premier plan et d'arrière-plan sous Linux

5 commandes amusantes à utiliser sous Linux et Terminal

Principes de base de la ligne de commande Linux - Travailler avec des fichiers et des répertoires