This works without precounting the number of lines in the file:
sed -ni '1{p;b}; 2{N;N;N;N}; $p; $!{N;s/^/word /;P;D}' filename
This buffers five lines and makes the substitution on the first line in the buffer and prints and deletes it. When the last line in the file is read, the buffer is printed without doing any substitutions.
1{p;b}
- read the first line, print it unchanged and branch to the end
2{N;N;N;N}
- when line 2 is read, append four more lines to create a five-line buffer
$p
- when the last line of the file is read, print the lines that remain in the buffer unchanged
$!
- when the current line is not the last line in the file...
N
- append the next line to the buffer (pattern space)
s/^/word /
- make the substitution on the first line in the buffer
P
- print only the first line in the buffer
D
- delete only the first line in the buffer
Note that this won't work properly for files that consist of fewer than 6 lines.
This is the same idea using AWK:
awk 'FNR == 1 {print; next} FNR == 2 {for (ptr = 0; ptr <= 4; ptr++) {buffer[ptr] = $0; getline}; ptr = 0} {sub(/^/, "word ", buffer[ptr]); print buffer[ptr]; buffer[ptr] = $0; ptr = (ptr + 1) % 5} END {for (i = 0; i <= 4; i++) {print buffer[(ptr + i) % 5]}}' filename > outputfile
mv outputfile filename
Here it is broken out on multiple lines:
FNR == 1 {
print
next
}
FNR == 2 {
for (ptr = 0; ptr <= 4; ptr++) {
buffer[ptr] = $0
getline
}
ptr = 0
}
{
sub(/^/, "word ", buffer[ptr])
print buffer[ptr]
buffer[ptr] = $0
ptr = (ptr + 1) % 5
}
END {
for (i = 0; i <= 4; i++) {
print buffer[(ptr + i) % 5]
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…