如何删除文件的最后n行?

4

我想知道是否有人能帮我。

我正在编写一个bash脚本,想要删除特定文件的最后12行。

我已经搜索过了,并且得到了以下代码:

head -n -12 /var/lib/pgsql/9.6/data/pg_hba.conf | tee /var/lib/pgsql/9.6/data/pg_hba.conf >/dev/null

但是这会彻底清除文件。我只想永久删除该文件的最后12行,以便用自己的规则覆盖它。请问我做错了什么?

Stack Overflow是一个关于编程和开发问题的网站。这个问题似乎不属于编程或开发范畴。请参阅帮助中心中的我可以在这里问什么样的问题。也许超级用户Unix&Linux Stack Exchange更适合提问。 - jww
4个回答

11

根据您的具体情况,有多种方法可供选择。对于小型、格式良好的文件(例如小于1M,具有常规大小的行),您可以在ex模式下使用Vim

ex -snc '$-11,$d|x' smallish_file.txt
  • -s -> 静默模式;这是批处理,不需要UI(更快)
  • -n -> 这里不需要撤销缓冲区
  • -c -> 命令列表
  • '$-11,$d' -> 选择从末尾到倒数第11行的11行内容并删除。注意使用单引号以防shell将$d解释为变量。
  • x -> "写入并退出"

如果您想要一个类似但更原始的回溯到'69年的编辑器,则可以使用ed

ed -s smallish_file.txt <<< $'-11,$d\nwq'
  • 注意单引号外面的$,这与上面的ex命令不同。

如果Vim/ex和Ed让你感到害怕,你可以使用sed并借助一些shell帮助:

sed -i "$(($(wc -l < smallish_file.txt) - 11)),\$d" smallish_file.txt
  • -i -> 原地修改:将更改写入文件
  • 共12行,减去11行即为1行。请注意转义了美元符号($),以便Shell不会对其进行插值。

但是对于较大的文件(比如超过几兆字节),使用上述方法效率不高。对于较大的文件,请使用中间/临时文件方法,就像其他答案所描述的那样。一个sed方法:

tac some_file.txt | sed '1,12d' | tac > tmp && mv tmp some_file.txt
  • 使用tac命令反转行顺序
  • 使用sed命令删除最后(现在是第一行)的12行
  • 使用tac命令将顺序反转回原始顺序

比sed更高效的方法是使用head:

head -n -12 larger_file.txt > tmp_file && mv tmp_file larger_file.txt
  • -n NUM:仅显示前NUM行。如果像我们这样取反,则显示最后NUM行。

但是,为了真正的效率——也许是对于非常大的文件或者不需要临时文件的情况——在原地截断文件会更好。与其他方法不同的是,其他方法涉及到用新内容完全覆盖整个旧文件的变化,而这一方法无论文件大小如何都几乎瞬间完成。

# In readable form:
BYTES=$(tail -12 really_large.txt | wc -c)
truncate -s -$BYTES really_large.txt

# Inline, perhaps as part of a script
truncate -s -$(tail -12 really_large.txt | wc -c) really_large.txt
truncate 命令可以将文件大小精确地设定为指定大小(以字节为单位)。如果文件太短,它会使其变大;如果文件太大,它将高效地截去多余的部分。它使用文件系统语义来进行操作,因此通常只需写入几个字节。其中的关键是计算截取位置:
  • -s -NUM -> 注意横杠/负号;表示要将文件减小 NUM 字节。
  • $(tail -12 really_large.txt | wc -c) -> 返回需要删除的字节数。
所以,你应该明智地选择!

我发现了一个和我同代的人!一些不错的见解!你能在edlin中也做到吗?;-) - Mark Setchell

4

就像这样:

head -n -12 test.txt > tmp.txt && cp tmp.txt test.txt

0
你可以使用临时文件来存储 head -n 的中间结果。
我认为以下代码应该可以工作:
 head -n -12 /var/lib/pgsql/9.6/data/pg_hba.conf  > /tmp/tmp.pg.hba.$$ && mv /tmp/tmp.pg.hba.$$ /var/lib/pgsql/9.6/data/pg_hba.conf

如果你要编写一个脚本,更易读和易于维护的代码应该是这样的:
 SRC_FILE=/var/lib/pgsql/9.6/data/pg_hba.conf
 TMP_FILE=/tmp/tmp.pg.hba.$$
 head -n -12 $SRC_FILE > $TMP_FILE && mv $TMP_FILE $SRC_FILE

在运行任何脚本之前,我建议先备份/var/lib/pgsql/9.6/data/pg_hba.conf文件。


F=/some/file; X=12; head -n -$X $F > /tmp/tmpfile && mv /tmp/tmpfile $F - rubo77
如果您使用的是Mac电脑:OS X版本的“head”命令不支持负数,但您可以安装core-utils并使用“ghead”命令。 - Dan Tanner

-1

简单明了的脚本

declare -i start
declare -i cnt
cat dummy
1
2
3
4
5
6
7
8
9
10
11
12
13
cnt=`wc -l dummy|awk '{print $1}'`
start=($cnt-12+1)
sed "${start},\$d" dummy

输出是第一行

1

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