vim/vi/sed:从文件末尾操作一定数量的行

11

就像我们可以在vim中从文件开头删除(或替换、复制等)第4到6行一样:

:4,6d 

我想删除(或替换、yank等)文件末尾第4行到第6行。也就是说,如果文件有15行,我会执行以下操作:

:10,12d

但是当他们不知道文件中有多少行时,就无法这样做——而我将在许多文件的批处理中使用它。我应该如何在vim和sed中执行此操作?

我确实看过这篇文章,但并没有发现它有用。

5个回答

10

好的,使用vim,你可以尝试以下内容-这相当直观,无论如何:

:$-4,$-5d

现在,使用 sed 我找不到确切的解决方法,但如果您可以使用除了 sed 之外的其他东西,这里有一个使用 headtail 的解决方案:

head -n -4 file.txt && tail -2 file.txt

谢谢。那么我该如何使用头和尾进行替换,就像我通常在sed和vim中做的那样呢? - Nike
tail -6 file.txt | head -2 | sed -e '...' 的翻译如下:请注意,sed和vim s命令的语法略有不同。您最好使用“>”保存文件,然后使用vim打开它。 - Forethinker

7

Vim中,你可以从$(代表最后一行)中减去行号,例如,在最后三行上执行:

:$-2,$substitute/...

在sed中,这并不容易,因为它作用于字符的流,并且不能简单地返回。您需要在“保留空间”中存储一些最近看到的行号,并在流的结尾处理保留空间。 以下是来自sed1line.txt的一些示例:

# print the last 10 lines of a file (emulates "tail")
sed -e :a -e '$q;N;11,$D;ba'

# print the last 2 lines of a file (emulates "tail -2")
sed '$!N;$!D'

# delete the last 2 lines of a file
sed 'N;$!P;$!D;$d'

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

6
从文件末尾往前数第4行到第6行:使用 tac 命令来反转文件。
tac filename | sed 4,6d | tac

2
你可以使用awk进行两次操作,第一次操作用于计算行数,第二次操作用于打印或删除你想要的行,例如:
awk 'NR==FNR{numLines++;next} {fromEnd = numLines - FNR} fromEnd > 6 || fromEnd < 4' file file

awk 'NR==FNR{numLines++;next} {fromEnd = numLines - FNR} fromEnd < 6 && fromEnd > 4' file file

1
这可能适用于您(GNU sed):
sed -r ':a;${s/([^\n]*\n){3}//;q};N;7,$!ba;P;D' file

这是通过在模式空间(PS)中创建一个6行的移动窗口,然后在遇到最后一行时删除前三行来实现的。

  • :a 是一个循环标签
  • ${s/([^\n]*\n){3}//;q} 删除文件末尾PS中的前三行并退出。
  • N 添加一个换行符和下一行到PS中。
  • 7,$!ba' 如果不是第7行到$(文件结尾)即第1行到第6行,则回到开头即标签:a
  • P;D 对于行范围7到$(文件结尾),打印PS中第一个换行符之前的内容,然后删除包括第一个换行符在内的所有内容,并开始新的循环。

倒数第二个子句默认创建窗口,因为行 16 被附加到 PS 中。从第 7 行到结尾,添加一行并打印删除第一行。

或者:

sed -e ':a' -e '$s/\([^\n]*\n\)\{3\}//' -e '$q' -e 'N' -e '7,$!ba' -e 'P' -e 'D' file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接