tr -c \\n 1 <testfile | #first transform every [^\n] char to a 1
grep -nF '' | #next get line numbers
paste -d: - testfile | #then paste it together with itself
sort -t: -nk2,2 #then sort on second field
... e il vincitore è ... linea 2, sembrerebbe.
2:1111:4for
4:11111:five!
1:1111111:seven/7
3:11111111:8 eight?
Ma il problema è che ogni linea deve essere più che raddoppiata per funzionare, quindi LINE_MAX è effettivamente dimezzata. La causa è che sta usando - cosa, una base 1? - per rappresentare la lunghezza della linea. Un approccio simile - e forse più ordinato - potrebbe essere quello di comprimere tali informazioni in streaming. La prima idea che mi viene in mente è che dovrei unexpand
:
tr -c \\n \ <testfile | #transform all [^\n] to <space>
unexpand -t10 | #squeeze every series of 10 to one tab
grep -nF '' | #and get the line numbers
sed 's/:/!d;=;:/;h;:big #sed compares sequential lines
$P;$!N; /\(:[^ ]*\)\( *\)\n.*\1.*\2/!D #newest line is shorter or...
g;/:./!q;b big' | #not; quit input entirely for blank line
sed -f - -e q testfile #print only first occurrence of shortest line
Che stampa ...
2
4for
Un altro, solo sed
:
sed -n '/^\n/D;s/\(.\)\(\n.*\)*/\1/g
$p;h; s// /g;G;x;n;//!g;H;s// /g
G; s/^\( *\)\(\n \1 *\)\{0,1\}\n//
D' <infile >outfile
La sintassi è conforme agli standard, ma ciò non garantisce che i vecchi sed
gestiranno \(reference-group\)\{counts\}
correttamente quelli che non lo fanno.
In pratica applica lo stesso regexp all'input ripetutamente, il che può essere molto utile quando è il momento di compilarli. Quel modello è:
\(.\)\(\n.*\)*
Che corrisponde a stringhe diverse in modi diversi. Per esempio:
string1\nstring2\nstring3
... corrisponde a s
in \1
e ''
alla stringa null in \2
.
1\nstring2\nstring3
... è abbinato a 1
in \1
e \nstring2\nstring3
in\2
\nstring2\nstring3
... corrisponde a \n
in \1
e ''
alla stringa null in \2
. Ciò sarebbe problematico se ci fosse la possibilità che si \n
verifichi una ewline in testa allo spazio del modello, ma i comandi /^\n/D
e //!g
sono usati per impedirlo. Ho usato, [^\n]
ma altri bisogni di questo piccolo script hanno reso la portabilità una preoccupazione e non ero soddisfatto dei molti modi in cui è spesso interpretato male. Inoltre, .
è più veloce.
\nstring2
string1
... match \n
e s
ancora in \1
ed entrambi ottengono la ''
stringa null in \2
. Le righe vuote non corrispondono affatto.
Quando il pattern viene applicato a livello g
vaginale, i due bias - sia il bias più standard a sinistra sia il \n
bias ewline inferiore destro - sono controbilanciati per effettuare uno skip. Alcuni esempi:
s/\(.\)\(\n.*\)*/\1:\2/g
s/\(.\)\(\n.*\)*/\2\1:/g
s/\(.\)\(\n.*\)*/\1: /g
s/\(.\)\(\n.*\)*/ :\2/g
... se tutti applicati (non in successione) alla seguente stringa ...
string1\nstring2
... lo trasformerà in ...
s:t:r:i:n:g:1:\nstring2
s:t:r:i:n:g:\nstring21:
s:t:r:i:n:g:1:
: : : : : : :\nstring2
Fondamentalmente uso regexp per gestire sempre solo la prima riga in qualsiasi spazio modello a cui lo applico. Ciò mi consente di destreggiarmi tra due diverse versioni di una linea di corrispondenza più breve mantenuta e la linea più recente senza ricorrere a cicli di test: ogni sostituzione applicata gestisce l'intero spazio del modello contemporaneamente.
Le diverse versioni sono necessarie per confronti letterali stringa / stringa - quindi deve esserci una versione di ogni riga in cui tutti i caratteri devono essere uguali. Ma ovviamente se l'uno o l'altro dovesse finire per essere effettivamente la prima riga più breve in ingresso, allora la linea stampata sull'output dovrebbe probabilmente essere la versione originale della linea - non quella che ho disinfettato / omogeneizzato per amor di confronto. E quindi ho bisogno di due versioni di ciascuno.
È un peccato che un'altra necessità sia molta commutazione del buffer per gestire lo stesso - ma almeno nessuno dei due buffer supera mai più delle quattro linee necessarie per rimanere aggiornato - e quindi forse non è terribile.
Ad ogni modo, per ogni ciclo la prima cosa che succede è una trasformazione sulla linea ricordata - perché l'unica copia effettivamente salvata è l'originale letterale - in ...
^ \nremembered line$
... e successivamente la n
riga di input ext sovrascrive qualsiasi vecchio buffer. Se non contiene almeno un singolo carattere, viene effettivamente ignorato. Sarebbe molto più semplice usare solo alla q
prima riga vuota, ma, beh, i miei dati di test avevano molti di questi e volevo gestire più paragrafi.
E quindi se contiene un personaggio, la sua versione letterale viene aggiunta alla linea ricordata e la sua versione di confronto spaziato viene posizionata all'inizio dello spazio del modello, in questo modo:
^ \n \nremembered line\nnew$
L'ultima sostituzione viene applicata a quello spazio modello:
s/^\( *\)\(\n \1 *\)\{0,1\}\n//
Quindi, se la nuova riga può adattarsi allo spazio necessario per contenere la riga memorizzata con almeno un carattere da risparmiare, le prime due righe vengono sostituite, altrimenti solo la prima.
Indipendentemente dal risultato, la prima riga nello spazio modello viene sempre D
eletta alla fine del ciclo prima di ricominciare. Ciò significa che se la nuova riga è più corta dell'ultima la stringa ...
new
... viene rimandato alla prima sostituzione del ciclo che rimuoverà sempre solo dal primo carattere newline attivo - e quindi rimane integro. Ma se non lo è, allora la stringa ...
remembered line\nnew
... inizierà invece il ciclo successivo e la prima sostituzione toglierà da esso la stringa ...
\nnew
...ogni volta.
Sull'ultima riga la riga memorizzata viene stampata sullo standard out, e quindi per i dati di esempio forniti, stampa:
4for
Ma, seriamente, usa tr
.