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

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

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

$ sed '2,4d' file

但是我不知道行号。我可以删除最后一行使用

$sed $d file

但是我想知道如何从末尾删除n行。请让我知道如何使用sed或其他方法。

283231 次浏览

我不知道sed,但它可以用head完成:

head -n -2 myfile.txt

你可以使用来实现。

使用

$ head --lines=-N file > new_file

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

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

通过这里的回答,您已经了解到sed并不是这个应用程序的最佳工具。

然而,我确实认为有一种方法可以在使用sed时做到这一点;这个想法是追加N行来保持空间,直到你能够读取而不击中EOF。当EOF被击中时,打印保留空间的内容并退出。

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

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

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

n=4
tac file.txt | sed "1,$n{d}" | tac

请注意

  • shell需要双引号"来计算sed命令中的$n变量。在单引号中,不执行插值。
  • tac是一个颠倒的cat,参见man 1 tac
  • sed中的{}用于分离$n和amp;d(如果不是,shell尝试插值不存在的$nd变量)

这可能为你工作(GNU sed):

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

sed俏皮话:

# 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

似乎就是你要找的东西。

你可以用wc -l <file>获取行总数,并使用

head -n <total lines - lines to remove> <file>

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

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

我更喜欢这个解决方案;

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

其中N是要删除的行数。

上面的大多数答案似乎都需要GNU命令/扩展:

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

有一个更方便携带的解决方案:

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

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

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

其中“10”是“n”。

删除最后4行:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'
sed -n ':pre
1,4 {N;b pre
}
:cycle
$!{P;N;D;b cycle
}' YourFile

posix版本

试试下面的命令:

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

我想到了这个,n是你想要删除的行数:

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

有点绕圈子,但我认为很容易理解。

  1. 把主文件的行数加起来
  2. 减去要从计数中删除的行数
  3. 打印出要保留并存储在临时文件中的行数
  4. 用临时文件替换主文件
  5. 删除临时文件
为了完整起见,我想添加我的解决方案。 我最终使用标准ed:

来完成此操作
ed -s sometextfile <<< $'-2,$d\nwq'

这将使用就地编辑删除最后两行(尽管它使用/tmp中的临时文件!!)

这将删除file中的最后3行:

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

要真正就地截断非常大的文件,我们有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

它可以通过3个步骤完成:

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

 n=`cat myfile |wc -l`

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

 x=$((n-3))

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

 sed "$x,\$d" myfile

使用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

这将删除最后12行

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

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

$ sed '2,4d' file

如果N = 5,可以使用tail命令进行反向操作

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

这种方法也可以在head -n -5 file命令不能运行的地方运行(比如在mac上!)。

在docker中,这为我工作:

head --lines=-N file_path > file_path
#!/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

类似于https://stackoverflow.com/a/24298204/1221137的解决方案,但编辑到位,没有硬编码行数:

n=4
seq $n | xargs -i sed -i -e '$d' my_file

假设你有几行代码:

    $ cat <<EOF > 20lines.txt
> 1
> 2
> 3
[snip]
> 18
> 19
> 20
> EOF

然后你可以抓取:

# leave last 15 out
$ head -n5 20lines.txt
1
2
3
4
5


# skip first 14
$ tail -n +15 20lines.txt
15
16
17
18
19
20

POSIX兼容的解决方案使用ex / vi,在上面的@Michel的解决方案的脉络。 @Michel的ed例子使用了“not-POSIX"Here-Strings。 增加$-1以将n行移到EOF($)中,或者只输入你想(d)删除的行。您可以使用ex来计数行号或执行任何其他Unix操作

给定文件:

cat > sometextfile <<EOF
one
two
three
four
five
EOF

执行:

ex -s sometextfile <<'EOF'
$-1,$d
%p
wq!
EOF

返回:

one
two
three
它使用POSIX Here-Docs,所以非常容易修改——特别是使用set -o vi和POSIX /bin/sh。 在这个问题上,“前任人格”;“;vim"应该是好的,但YMMV.