Grep la première ligne la plus longue
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
La commande est inhabituellement difficile à lire sans pratique, car elle mélange la syntaxe shell et regexp.
Pour l'explication, je vais d'abord utiliser le pseudocode simplifié. Les lignes commençant par ##
ne sont pas exécutées dans le shell.
Ce code simplifié utilise le nom de fichier F et laisse de côté les citations et des parties de regexps pour des raisons de lisibilité.
Comment ça marche
La commande a deux parties, une grep
- et une wc
invocation:
## grep "^.{$( wc -L F )}$" F
Le wc
est utilisé dans une extension de processus $( ... )
, il est donc exécuté avant grep
. Il calcule la longueur de la plus longue ligne. La syntaxe d'expansion du shell est mélangée à la syntaxe du modèle d'expression régulière d'une manière qui prête à confusion, donc je décomposerai l'extension du processus:
## wc -L F
42
## grep "^.{42}$" F
Ici, l’extension du processus a été remplacée par la valeur qu’elle renverrait, créant la grep
ligne de commande utilisée. Nous pouvons maintenant lire l’expression régulière plus facilement: elle correspond exactement de start ( ^
) à end ( $
) de la ligne. L'expression entre eux correspond à n'importe quel caractère sauf newline, répété 42 fois. Combinées, il s’agit de lignes comportant exactement 42 caractères.
Revenons maintenant aux commandes réelles du shell: L' grep
option -E
( --extended-regexp
) permet de ne pas échapper à la {}
lisibilité. Option -m 1
( --max-count=1
) le fait s'arrêter après la première ligne. Le <
dans la wc
commande écrit le fichier dans son stdin, pour empêcher l' wc
impression du nom du fichier avec la longueur.
Quelles lignes les plus longues?
Pour rendre les exemples plus lisibles avec le nom de fichier apparaissant deux fois, je vais utiliser une variable f
pour le nom de fichier; Chacun $f
dans l'exemple pourrait être remplacé par le nom du fichier.
f="file.txt"
Affiche la première ligne la plus longue - la première ligne aussi longue que la plus longue:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Afficher toutes les lignes les plus longues - toutes les lignes aussi longues que la ligne la plus longue:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Affiche la dernière ligne la plus longue - la dernière ligne aussi longue que la ligne la plus longue:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Afficher la ligne la plus longue unique - la ligne la plus longue plus longue que toutes les autres lignes, ou échouer:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(La dernière commande est encore plus inefficace que les autres, car elle répète la commande grep complète. Elle doit évidemment être décomposée de manière à ce que la sortie wc
et les lignes écrites par grep
soient enregistrées dans des variables.
Notez que toutes les lignes les plus longues peuvent en réalité être toutes les lignes. Pour enregistrer dans une variable, seules les deux premières lignes doivent être conservées.)