Grep la prima linea più lunga
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Il comando è insolitamente difficile da leggere senza pratica perché mescola la sintassi shell e regexp.
Per spiegazione, userò prima lo pseudocodice semplificato. Le linee che iniziano con ##
non vengono eseguite nella shell.
Questo codice semplificato utilizza il nome del file F, e lascia fuori citazione e parti di regexps per la leggibilità.
Come funziona
Il comando ha due parti, a grep
- e una wc
chiamata:
## grep "^.{$( wc -L F )}$" F
La wc
viene utilizzato in un processo di espansione, $( ... )
, quindi viene eseguito prima grep
. Calcola la lunghezza della linea più lunga. La sintassi di espansione della shell è mescolata con la sintassi del modello di espressione regolare in modo confuso, quindi decomporrò l'espansione del processo:
## wc -L F
42
## grep "^.{42}$" F
Qui, l'espansione del processo è stata sostituita con il valore che avrebbe restituito, creando la grep
riga di comando utilizzata. Ora possiamo leggere più facilmente l'espressione regolare: corrisponde esattamente dall'inizio ( ^
) alla fine ( $
) della riga. L'espressione tra loro corrisponde a qualsiasi carattere tranne newline, ripetuto per 42 volte. Combinati, ovvero linee composte da esattamente 42 caratteri.
Ora, torniamo ai comandi reali della shell: l' grep
opzione -E
( --extended-regexp
) consente di non sfuggire alla {}
leggibilità. L'opzione -m 1
( --max-count=1
) lo fa arrestare dopo aver trovato la prima riga. Il <
nel wc
comando scrive il file nel suo stdin, per evitare wc
di stampare il nome del file insieme alla lunghezza.
Quali linee più lunghe?
Per rendere più leggibili gli esempi con il nome del file che si verifica due volte, userò una variabile f
per il nome del file; Ciascuno $f
nell'esempio potrebbe essere sostituito dal nome del file.
f="file.txt"
Mostra la prima linea più lunga - la prima linea che è lunga quanto la linea più lunga:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Mostra tutte le linee più lunghe - tutte le linee lunghe quanto la linea più lunga:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Mostra l' ultima riga più lunga - l'ultima riga che è lunga quanto la riga più lunga:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Mostra la linea più lunga singola - la linea più lunga più lunga di tutte le altre linee o non riesce:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(L'ultimo comando è ancora più inefficiente degli altri, poiché ripete il comando grep completo. Dovrebbe ovviamente essere decomposto in modo che l'output di wc
e le righe scritte da grep
vengano salvati in variabili.
Notare che tutte le righe più lunghe possono effettivamente essere tutte righe Per salvare in una variabile, è necessario mantenere solo le prime due righe.)