如何使用 sed 删除文件的最后 n 行

Posted

技术标签:

【中文标题】如何使用 sed 删除文件的最后 n 行【英文标题】:How to use sed to remove the last n lines of a file 【发布时间】:2012-11-03 01:18:24 【问题描述】:

我想从文件末尾删除一些 n 行。这可以使用 sed 完成吗?

例如,要删除从 2 到 4 的行,我可以使用

$ sed '2,4d' file

但我不知道行号。我可以使用

删除最后一行
$sed $d file

但我想知道从末尾删除 n 行的方法。请让我知道如何使用 sed 或其他方法来做到这一点。

【问题讨论】:

@arashkordi:使用文件顶部的行数,而不是底部。 superusers上的相关问题。 // ,也许考虑改写问题以使其比just sed更笼统? sed $d file 返回错误。相反,$d 应该在引号内,如下所示:sed '$d' file 【参考方案1】:

我不知道sed,但可以使用head

head -n -2 myfile.txt

【讨论】:

+1 为简单起见。等效的 sed 命令很丑:sed -e :a -e '$d;N;2,5ba' -e 'P;D' file(最后 5 行为,5)。 请注意,这适用于 head 的某些版本,但不是标准的。事实上,head 的标准规定:The application shall ensure that the number option-argument is a positive decimal integer. 添加到@WilliamPursell 的答案...在 Mac OS 默认外壳上,这不起作用。 在 BSD 上也不是,但问题被标记为 Linux。 减 1,因为除了 osx,这在 Ubuntu14 上对我不起作用 - head: illegal line count -- -2【参考方案2】:

如果硬编码 n 是一个选项,您可以使用顺序调用 sed。例如,要删除最后三行,请将最后一行删除三次:

sed '$d' file | sed '$d' | sed '$d'

【讨论】:

这个,加上 -i 来编辑文件而不是将其转储到标准输出,对我有用。 不知道为什么 |管道不工作,;为我工作。【参考方案3】:

来自sed one-liners:

# 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

似乎正是你想要的。

【讨论】:

@Thor 您可以通过更改'$d;N;2,10ba' 中的10 来更改从文件中删除的行数 @AlexejMagura:我在评论答案的早期版本。 对不起,我对 sed 命令还很陌生,这让我很困惑。如何使用此命令指定要应用的文件?【参考方案4】:

一个有趣而简单的sedtac 解决方案:

n=4
tac file.txt | sed "1,$nd" | tac

注意

shell 需要双引号 " 来评估 sed 命令中的 $n 变量。在单引号中,不会执行插值。 tac 是一个 cat 反转,请参阅 man 1 tac sed 中的 用于分隔$nd(如果不是,shell 会尝试插入不存在的$nd 变量)

【讨论】:

@MichaelDurrant port info coreutils || brew info coreutils;【参考方案5】:

使用sed,但让shell 计算,目标是通过给出一个范围(删除最后23 行)来使用d 命令:

sed -i "$(($(wc -l < file)-22)),\$d" file

从内到外删除最后 3 行:

$(wc -l < file)

给出文件的行数:比如 2196

我们要删除最后 23 行,所以对于左侧或范围:

$((2196-22))

给:2174 因此shell解释后的原始sed是:

sed -i '2174,$d' file

-i 进行就地编辑,文件现在是 2173 行!

如果要将其保存到新文件中,代码为:

sed -i '2174,$d' file > outputfile

【讨论】:

【参考方案6】:

您可以为此使用 head

使用

$ head --lines=-N file &gt; new_file

其中 N 是要从文件中删除的行数。

原始文件的内容减去最后 N 行现在在 new_file

【讨论】:

【参考方案7】:

为了完整起见,我想添加我的解决方案。 我最终用标准的ed 做到了这一点:

ed -s sometextfile <<< $'-2,$d\nwq'

这会使用就地编辑删除最后 2 行(尽管它确实使用了 /tmp 中的临时文件!!)

【讨论】:

【参考方案8】:

要真正就地截断非常大的文件,我们有truncate 命令。 它不知道行,但是tail + wc 可以将行转换为字节:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

如果同时写入文件,则存在明显的竞争条件。 在这种情况下,使用head 可能会更好——它从文件的开头开始计算字节数(mind disk IO),所以我们总是会在行边界上截断(如果文件被主动写入,可能会比预期的行更多):

truncate -s $(head -n -$lines $file | wc -c) $file

如果您尝试使用密码代替用户名登录失败,那么方便的单行:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure

【讨论】:

【参考方案9】:

这可能对你有用(GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file

【讨论】:

不错。您错过了结尾的撇号 (')。 抱歉这么晚发表评论,但我尝试(适用于我的 AIX/posix)它未能打印除最后一行之外的所有内容。阅读代码,我不明白最后四行是如何被删除的,显式循环位于前 4 行,所以它肯定会在 dDP 之后循环使用 GNU sed 而不是 posix 版本.似乎在D 之后没有打印行并保留在工作缓冲区中以进行新循环,而不会传递到操作行的“结束”。 @NeronLeVelu 程序将 4 行的窗口读取到模式空间中,然后附加下一行并打印第一行,直到到达文件末尾并删除其余行。 @potong 是的,我在 GNU sed 上进行了测试,它在 posix 卸载它的行之间保留了缓冲区,D 产生了相反的效果。【参考方案10】:

以上大部分答案似乎都需要 GNU 命令/扩展:

    $ head -n -2 myfile.txt
    -2: Badly formed number

对于更便携的解决方案:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

     perl -ne 'push(@buf,$_);ENDprint @buf[0 ... $#buf-10]'

     awk 'buf[NR-1]=$0;END for ( i=0; i < (NR-10); i++) print buf[i]; '

其中“10”是“n”。

【讨论】:

【参考方案11】:

有了这里的答案,您已经知道 sed 不是这个应用程序的最佳工具。

但是我确实认为使用 sed 可以做到这一点;这个想法是附加 N 行以保留空间,直到您能够阅读而不会碰到 EOF。当遇到 EOF 时,打印保持空间的内容并退出。

sed -e '$!N;N;N;N;N;N;H;' -e x

上面的 sed 命令将省略最后 5 行。

【讨论】:

【参考方案12】:

分三步完成:

a) 计算要编辑的文件的行数:

 n=`cat myfile |wc -l`

b) 从该数字中减去要删除的行数:

 x=$((n-3))

c) 告诉 sed 从该行号 ($x) 删除到末尾:

 sed "$x,\$d" myfile

【讨论】:

数学不好。如果您必须删除 3 行,则减去 3 但添加 1。根据您的数学计算,如果文件有 10 行,则 10 - 3 = 7 并且您使用 sed 删除第 7 到 10 行,即 4 行,而不是3.【参考方案13】:

您可以使用wc -l &lt;file&gt; 获取总行数并使用

head -n &lt;total lines - lines to remove&gt; &lt;file&gt;

【讨论】:

【参考方案14】:

试试下面的命令:

n = line number
tail -r file_name | sed '1,nd' | tail -r

【讨论】:

请解释这是如何工作的。仅供参考 - 要初始化 shell 变量,= 周围不应有空格。 @codeforester 第一行是我猜的评论。他只是使用tail -r 而其他人使用tac 来反转行顺序,并使最后的n 行成为n 的第一行。【参考方案15】:

这将删除 file 的最后 3 行:

for i in $(seq 1 3); do sed -i '$d' file; done;

【讨论】:

这对于大文件来说太昂贵了——整个文件必须被读取和重写 n 次!和sed 一样多的叉子。 虽然这可能不是最有效的解决方案,但它是最直接和容易理解的【参考方案16】:

我更喜欢这个解决方案;

head -$(gcalctool -s $(cat file | wc -l)-N) file

其中 N 是要删除的行数。

【讨论】:

【参考方案17】:
sed -n ':pre
1,4 N;b pre
    
:cycle
$!P;N;D;b cycle
  ' YourFile

posix版本

【讨论】:

【参考方案18】:

删除最后 4 行:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   

【讨论】:

与头部相比有点沉重(尤其是在资源方面)。至少tac file | sed '1,4d' | tac,因为排序然后删除前缀会消耗大量资源。 @NeronLeVelu 你是对的但是没有tac 命令是一些系统(例如FreeBSD?)【参考方案19】:

我想出了这个,其中 n 是您要删除的行数:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

这是一个小环岛,但我认为它很容易遵循。

    统计主文件的行数 从计数中减去要删除的行数 打印出要保留并存储在临时文件中的行数 用临时文件替换主文件 删除临时文件

【讨论】:

【参考方案20】:

对于删除文件的最后N行,可以使用相同的概念

$ sed '2,4d' file

您可以使用组合尾命令来反转文件:如果 N 为 5

$ tail -r file | sed '1,5d' file | tail -r > file

这种方式也可以在 head -n -5 file 命令不运行的地方运行(就像在 mac 上一样!)。

【讨论】:

【参考方案21】:

在 docker 中,这对我有用:

head --lines=-N file_path >> file_path

【讨论】:

【参考方案22】:
#!/bin/sh

echo 'Enter the file name : '
read filename

echo 'Enter the number of lines from the end that needs to be deleted :'
read n

#Subtracting from the line number to get the nth line
m=`expr $n - 1`

# Calculate length of the file
len=`cat $filename|wc -l`

#Calculate the lines that must remain
lennew=`expr $len - $m`

sed "$lennew,$ d" $filename

【讨论】:

从系统中读取任意文件并选择任意长度【参考方案23】:

这将删除最后 12 行

sed -n -e :a -e '1,10!P;N;D;;N;ba'

【讨论】:

请稍作解释。

以上是关于如何使用 sed 删除文件的最后 n 行的主要内容,如果未能解决你的问题,请参考以下文章

sed 删除

这个sed命令如何:“sed -e:a -e'$ d; N; 2,10ba'-e'P; D'”工作?

Linux三剑客(sed)-编辑匹配到的文本

sed 删除最后几行 和删除指定行 awk使用

sed 或 awk:删除模式后面的 n 行

如何在 Linux 中删除超大的文件