p='[:punct:]' s='[:space:]'
sed -Ee'1!{/\n/!b' -e\} \
-e's/(\n*)(.*)/ \2 \1/' \
-e"s/is[$p]?[$s]/\n&/g" \
-e"s/([^$s])\n/\1/g;1G" \
-e:c -e"s/\ni(.* )\n{3}/u\1/" \
-e"/\n$/!s/\n//g;/\ni/G" \
-e's//i/;//tc' \
-e's/^ (.*) /\1/;P;$d;N;D'
Dieses Bit von sedträgt nur eine Liste von isEreignissen von einer Zeile zur nächsten. Es sollte zuverlässig so viele ises pro Zeile verarbeiten, wie Sie darauf werfen, und es muss dabei keine alten Zeilen puffern - es behält nur ein einzelnes Zeilenumbruchzeichen für jedes is, auf das es trifft, das nicht Teil eines anderen Wortes ist.
Das Ergebnis ist, dass nur das dritte Vorkommen in einer Datei geändert wird - und die Anzahl pro Zeile übertragen wird. Wenn also eine Datei so aussieht:
1. is is isis
2. is does
... es wird gedruckt ...
1. is is isis
2. us does
Zunächst werden Randfälle behandelt, indem am Kopf und am Ende jeder Zeile ein Leerzeichen eingefügt wird. Dies erleichtert die Ermittlung von Wortgrenzen.
Als nächstes wird nach gültigen ises \ngesucht, indem eine Ewline eingefügt wird, bevor alle Vorkommen isunmittelbar vor null oder einem Satzzeichen stehen, gefolgt von einem Leerzeichen. Es führt einen weiteren Durchgang durch und entfernt alle \nEwlines, denen unmittelbar ein Nicht-Leerzeichen vorangestellt ist. Diese zurückgelassenen Markierungen stimmen überein is.und isaber nicht thisoder ?is.
Als nächstes wird jeder Marker am Ende der Zeichenfolge \nigesammelt. Bei jeder Übereinstimmung in einer Zeile wird eine \nneue Zeile an das Ende der Zeichenfolge angehängt und durch entweder ioder ersetzt u. Wenn \nsich am Ende des Strings 3 Ewlines in einer Reihe befinden, wird das u - sonst das i verwendet. Das erste Mal, wenn au verwendet wird, ist auch das letzte Mal - der Ersatz löst eine Endlosschleife aus, die auf get line, print line, get line, print line,usw. hinausläuft.
Am Ende jedes Try-Loop-Zyklus werden die eingefügten Leerzeichen bereinigt, nur bis zur ersten auftretenden neuen Zeile im Musterbereich gedruckt und erneut ausgeführt.
Ich werde einen look-Befehl am Kopf der Schleife hinzufügen wie:
l; s/\ni(.* )\n{9}/u\1/...
... und schauen Sie sich an, was es mit dieser Eingabe macht:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged is.
... also hier ist was es tut:
hai this \nis linux. \n$ #behind the scenes
hai this is linux. #actually printed
hai this \nis unix. \n\n$ #it builds the marker string
hai this is unix.
\n\n\n$ #only for lines matching the
\n\n\n$ #pattern - and not otherwise.
hai this \nis mac. \n\n\n$ #here's the match - 3 ises so far in file.
hai this us mac. #printed
hai this is unchanged is. #no look here - this line is never evaled
Es macht vielleicht mehr Sinn mit mehr ises pro Zeile:
nthword()( p='[:punct:]' s='[:space:]'
sed -e '1!{/\n/!b' -e\} \
-e 's/\(\n*\)\(.*\)/ \2 \1/' \
-e "s/$1[$p]\{0,1\}[$s]/\n&/g" \
-e "s/\([^$s]\)\n/\1/g;1G;:c" \
-e "${dbg+l;}s/\n$1\(.* \)\n\{$3\}/$2\1/" \
-e '/\n$/!s/\n//g;/\n'"$1/G" \
-e "s//$1/;//tc" -e 's/^ \(.*\) /\1/' \
-e 'P;$d;N;D'
)
Das ist praktisch das Gleiche, aber mit POSIX BRE und rudimentärer Argumentation geschrieben.
printf 'is is. is? this is%.0s\n' {1..4} | nthword is us 12
... bekommt ...
is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is
... und wenn ich aktiviere ${dbg}:
printf 'is is. is? this is%.0s\n' {1..4} |
dbg=1 nthword is us 12
... wir können es iterieren sehen ...
\nis \nis. \nis? this \nis \n$
is \nis. \nis? this \nis \n\n$
is is. \nis? this \nis \n\n\n$
is is. is? this \nis \n\n\n\n$
is is. is? this is
\nis \nis. \nis? this \nis \n\n\n\n\n$
is \nis. \nis? this \nis \n\n\n\n\n\n$
is is. \nis? this \nis \n\n\n\n\n\n\n$
is is. is? this \nis \n\n\n\n\n\n\n\n$
is is. is? this is
\nis \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n$
is \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n\n$
is is. \nis? this \nis \n\n\n\n\n\n\n\n\n\n\n$
is is. is? this \nis \n\n\n\n\n\n\n\n\n\n\n\n$
is is. is? this us
is is. is? this is