删除bash中某行之后的所有内容

时间:2017-07-16 06:41:50

标签: bash text

我想知道是否有办法在bash中的某个文本文件行之后删除所有内容。所以说有一个10行的文本文件,我想删除第4行之后的每一行,所以只剩下前4行,我该怎么做呢?

4 个答案:

答案 0 :(得分:2)

您可以使用GNU sed

sed -i '5,$d' file.txt

也就是说,5,$表示范围行5直到结束,d表示删除。 只剩下前4行。 -i标志告诉sed就地编辑文件。

如果您只有BSD sed,则-i标志需要备份文件后缀:

sed -i.bak '5,$d' file.txt

正如@ephemient指出的那样,虽然这个解决方案很简单, 这是低效的,因为sed仍然会在文件结尾之前读取输入,这是不必要的。

正如@agc指出的那样,我的第一个提案的反逻辑实际上可能更直观。也就是说,不要默认打印(-n标志), 并明确打印范围1,4

sed -ni.bak 1,4p file.txt

另一个简单的替代方案,假设前4行不会过长,因此它们很容易适合内存,并且假设第4行以换行符结尾, 你可以将前4行读入内存,然后覆盖文件:

lines=$(head -n 4 file.txt)
echo "$lines" > file.txt

答案 1 :(得分:2)

sed方法@janos简单但效率低下。它将读取原始文件中的每一行,即使它可以忽略的行(虽然可以使用4q修复),-i实际创建一个新文件(它重命名以替换原始文件) 。还有一个烦人的地方你需要使用sed -i '5,$d' file.txt和GNU sed,sed -i '' '5,$d' file.txt和BSD sed,以便删除现有文件而不是留下备份。

执行较少I / O的另一种方法:

dd bs=1 count=0 if=/dev/null of=file.txt \
    seek=$(grep -b ^ file.txt | tail -n+5 | head -n1 | cut -d: -f1)
  • grep -b ^ file.txt打印出每行的字节偏移量,例如

    $ yes | grep -b ^
    0:y
    2:y
    4:y
    ...
    
  • tail -n+5跳过前4行,输出5 th 和后续行

  • head -n1只接受下一行(例如只有5 th 行)

    head读取一行后,它将退出。这会导致tail退出,因为它无处可输出。这导致grep出于同样的原因退出。因此,file.txt的其余部分不需要进行检查。

  • cut -d: -f1仅占用:之前的第一部分(字节偏移量)

  • dd bs=1 count=0 if=/dev/null of=file.txt seek=N

    • 使用1字节的块大小,设法阻止N的<{1}}

    • file.txt复制0个大小为1个字节的块到/dev/null

    • 在此截断file.txt(因为未提供file.txt

    简而言之,这将删除{<1>}的5 th 和后续行中的所有数据。

    在Linux上有一个名为conv=notrunc的命令,可以类似地扩展或截断文件,但这不是可移植的。

UNIX文件系统支持有效截断文件,这些命令是可移植的。缺点是写出更多的工作。

(另外,file.txt会向stderr打印一些不必要的统计信息,如果文件少于5行,则会以错误退出,但在这种情况下,它会保留现有文件内容,因此行为仍然是正确的。如果需要,也可以解决这些问题。)

答案 2 :(得分:1)

Janos' answerephemient's answercdark's comment的细微优化:

  1. 更简单(更快)sed代码:

    sed -i 4q file
    
  2. 当过滤器util不能直接编辑文件时,就有了 sponge

    head -4 file | sponge file
    
  3. Linux 最有效的可能是truncatecoreutils同级到fallocate的同义词,它提供相同的最小 I / O ephemient 更复杂但更便携的基于dd的答案

    truncate -s `head -4 file | wc -c` file
    

答案 3 :(得分:0)

使用GNU awk(v.4.1.0 +,见here)。首先,我们创建一个测试文件(注意免责声明):

$ seq 1 10 > file     # THIS WILL OVERWRITE FILE NAMED file WITH TEST DATA

然后代码和验证(将修改原始文件命名为file):

$ awk -i inplace 'NR<=4' file
$ cat file
1
2
3
4

说明:

$ awk -i inplace '   # edit is targetted to the original file (try without -i ...)
NR<=4                # output first 4 records
' file               # file

您也可以退出NR==5,如果您将程序的输出重定向到新文件(删除#以获取操作),这将更快,这与{{1}相同}:

head -4 file > new_file

测试时,请不要先忘记$ awk 'NR==5{exit}1' file # > new_file 部分。