如何使用 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上的相关问题。 // ,也许考虑改写问题以使其比justsed
更笼统?
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】:
一个有趣而简单的sed
和tac
解决方案:
n=4
tac file.txt | sed "1,$nd" | tac
注意
shell 需要双引号"
来评估 sed
命令中的 $n
变量。在单引号中,不会执行插值。
tac
是一个 cat
反转,请参阅 man 1 tac
sed
中的
用于分隔$n
和d
(如果不是,shell 会尝试插入不存在的$nd
变量)
【讨论】:
@MichaelDurrantport 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 > 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 行,所以它肯定会在 d
、D
或 P
之后循环使用 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 <file>
获取总行数并使用
head -n <total lines - lines to remove> <file>
【讨论】:
【参考方案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 行的主要内容,如果未能解决你的问题,请参考以下文章