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
... und der Gewinner ist ... Zeile 2, wie es scheint.
2:1111:4for
4:11111:five!
1:1111111:seven/7
3:11111111:8 eight?
Das Problem dabei ist jedoch, dass jede Zeile mehr als doppelt so lang sein muss, damit sie funktioniert - LINE_MAX wird also effektiv halbiert. Die Ursache ist, dass es verwendet - was, eine Basis 1? - um die Länge der Linie darzustellen. Ein ähnlicher - und vielleicht ordentlicherer - Ansatz könnte darin bestehen, diese Informationen im Stream zu komprimieren. Die erste Idee in dieser Richtung, die mir einfällt, ist, dass ich es tun unexpand
sollte:
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
Das druckt ...
2
4for
Ein anderer, nur 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
Die Syntax ist standardkonform - aber das ist keine Garantie dafür, dass alle alten sed
die \(reference-group\)\{counts\}
richtigen Befehle ausführen - viele nicht.
Es wendet grundsätzlich den gleichen Ausdruck auf wiederholte Eingaben an - was sehr nützlich sein kann, wenn es an der Zeit ist, sie zu kompilieren. Dieses Muster ist:
\(.\)\(\n.*\)*
Womit verschiedene Saiten auf unterschiedliche Weise übereinstimmen. Beispielsweise:
string1\nstring2\nstring3
... wird mit s
in \1
und ''
der Nullzeichenfolge in abgeglichen \2
.
1\nstring2\nstring3
... passt zu 1
in \1
und \nstring2\nstring3
in\2
\nstring2\nstring3
... wird mit \n
in \1
und ''
der Nullzeichenfolge in abgeglichen \2
. Dies wäre problematisch, wenn \n
am Anfang des Musterraums eine ewline auftreten könnte - dies wird jedoch mit den Befehlen /^\n/D
, und //!g
verhindert. Ich habe verwendet, [^\n]
aber andere Bedürfnisse für dieses kleine Skript machten die Portabilität zu einem Problem und ich war nicht zufrieden mit den vielen Möglichkeiten, die es oft falsch interpretiert. Plus .
ist schneller.
\nstring2
string1
... match \n
and s
again in \1
und beide bekommen den ''
Nullstring in \2
. Leerzeilen stimmen überhaupt nicht überein.
Wenn das Muster g
lobal angewendet wird, werden die beiden Verzerrungen - sowohl die am weitesten links liegende Standardverzerrung als auch die am \n
wenigsten rechts liegende Ewline-Verzerrung - ausgeglichen, um ein Überspringen zu bewirken. Einige Beispiele:
s/\(.\)\(\n.*\)*/\1:\2/g
s/\(.\)\(\n.*\)*/\2\1:/g
s/\(.\)\(\n.*\)*/\1: /g
s/\(.\)\(\n.*\)*/ :\2/g
... wenn alles (nicht nacheinander) auf die folgende Zeichenfolge angewendet wurde ...
string1\nstring2
... verwandelt es in ...
s:t:r:i:n:g:1:\nstring2
s:t:r:i:n:g:\nstring21:
s:t:r:i:n:g:1:
: : : : : : :\nstring2
Grundsätzlich verwende ich den regulären Ausdruck, um immer nur die erste Zeile in einem Musterraum zu behandeln, auf den ich ihn anwende. Dadurch kann ich zwei verschiedene Versionen einer beibehaltenen Linie mit dem kürzesten Übereinstimmungswert und der neuesten Linie unter einen Hut bringen, ohne auf Testschleifen zurückgreifen zu müssen - jede angewendete Substitution behandelt den gesamten Musterraum auf einmal.
Die verschiedenen Versionen sind für wörtliche Zeichenfolgen- / Zeichenfolgenvergleiche erforderlich. Daher muss es eine Version jeder Zeile geben, in der garantiert alle Zeichen gleich sind. Aber natürlich sollte die eine oder andere Zeile tatsächlich die am frühesten auftretende kürzeste Eingabezeile sein, dann sollte die zur Ausgabe gedruckte Zeile wahrscheinlich die Originalversion der Zeile sein - nicht die, die ich zu Vergleichszwecken bereinigt / homogenisiert habe. Und so brauche ich jeweils zwei Versionen.
Es ist bedauerlich, dass eine weitere Notwendigkeit darin besteht, dass viel Puffer gewechselt wird, um dasselbe zu handhaben - aber zumindest überschreitet keiner der Puffer jemals mehr als die vier Leitungen, die erforderlich sind, um auf dem neuesten Stand zu bleiben - und daher ist es möglicherweise nicht schrecklich.
Jedenfalls geschieht für jeden Zyklus als Erstes eine Transformation auf der erinnerten Zeile - denn die einzige tatsächlich gespeicherte Kopie ist das wörtliche Original - in ...
^ \nremembered line$
... und danach n
überschreibt die ext-Eingabezeile irgendeinen alten Puffer. Wenn es nicht mindestens ein einzelnes Zeichen enthält, wird es effektiv ignoriert. Es wäre viel einfacher, wenn ich nur q
die erste leere Zeile ausfüllen würde, aber meine Testdaten enthielten viele davon, und ich wollte mit mehreren Absätzen umgehen.
Wenn es also ein Zeichen enthält, wird seine Literalversion an die gespeicherte Zeile angehängt, und seine beabstandete Vergleichsversion wird wie folgt am Kopf des Musterraums positioniert:
^ \n \nremembered line\nnew$
Zuletzt wird eine Ersetzung auf diesen Musterraum angewendet:
s/^\( *\)\(\n \1 *\)\{0,1\}\n//
Wenn die neue Zeile also in den Platz passt, der zur Aufnahme der gespeicherten Zeile mit mindestens einem freien Zeichen erforderlich ist, werden die ersten beiden Zeilen ersetzt, ansonsten nur die erste.
Unabhängig vom Ergebnis wird die erste Zeile im Musterbereich immer D
am Ende des Zyklus gelöscht, bevor erneut gestartet wird. Dies bedeutet, dass, wenn die neue Zeile kürzer als die letzte ist, die Zeichenfolge ...
new
... wird an die erste Vertretung im Zyklus zurückgeschickt, die sich immer nur vom ersten Zeilenumbruch abhebt - und bleibt somit ganz. Aber wenn es nicht so ist, dann die Zeichenfolge ...
remembered line\nnew
... beginnt stattdessen mit dem nächsten Zyklus, und die erste Ersetzung entfernt die Zeichenfolge ...
\nnew
...jedes Mal.
In der allerletzten Zeile wird die gespeicherte Zeile als Standardausgabe ausgegeben, und für die angegebenen Beispieldaten wird Folgendes ausgegeben:
4for
Aber im Ernst, benutze tr
.