在大文件的开头和结尾添加行

在大文件的开头和结尾添加行

我有这样的场景:在大文件的开头和结尾添加行。

我已经尝试过,如下所示。

  • 对于第一行:

    sed -i '1i\'"$FirstLine" $Filename
    
  • 对于最后一行:

    sed -i '$ a\'"$Lastline" $Filename  
    

但此命令的问题在于它附加文件的第一行并遍历整个文件。对于最后一行,它再次遍历整个文件并附加最后一行。由于文件非常大(14GB),这需要很长时间。

如何在仅读取文件一次的情况下在文件的开头添加一行,在文件的末尾添加另一行?

答案1

sed -i使用临时文件作为实现细节,这就是您正在经历的;但是,将数据添加到数据流的开头而不覆盖现有内容需要重写文件,即使避免sed -i.

如果重写文件不可行,您可能会考虑在读取文件时对其进行操作,例如:

{ echo some prepended text ; cat file ; } | command

另外,sed 用于编辑流——文件不是流。使用专门用于此目的的程序,例如 ed 或 ex。 sed选项-i不仅不可移植,还会破坏文件的任何符号链接,因为它实际上会删除文件并重新创建它,这是毫无意义的。

您可以使用单个命令来完成此操作,如下ed所示:

ed -s file << 'EOF'
0a
prepend these lines
to the beginning
.
$a
append these lines
to the end
.
w
EOF

请注意,根据您的 ed 实现,它可能会使用分页文件,要求您至少有那么多的可用空间。

答案2

请注意,如果您想避免在磁盘上分配文件的整个副本,您可以这样做:

sed '
1i\
begin
$a\
end' < file 1<> file

这利用了这样一个事实:当它的 stdin/stdout 是一个文件时,sed 按块读取和写入。因此,在这里,只要您添加的第一行小于sed的块大小(应该类似于 4k 或 8k),它就可以覆盖它正在读取的文件。

请注意,如果由于某种原因sed失败(被杀死、机器崩溃......),您最终将得到一半的文件处理,这意味着第一行大小的一些数据在中间的某个地方丢失。

另请注意,除非您sed是 GNU sed,否则不适用于二进制数据(但由于您使用的是-i,所以您正在使用 GNU sed )。

答案3

以下是一些选择(所有这些都会创建文件的新副本,因此请确保有足够的空间):

  • 简单的回声/猫

    echo "first" > new_file; cat $File >> new_file; \
      echo "last" >> new_file; 
    
  • awk/gawk 等

    gawk 'BEGIN{print "first\n"}{print}END{print "last\n"}' $File > NewFile 
    

    awk及其同类逐行读取文件。该BEGIN{}块在第一行之前执行,END{}在最后一行之后执行。所以,上面的命令的意思是print "first" at the beginning, then print every line in the file and print "last" at the end

  • 珀尔

    perl -ne 'BEGIN{print "first\n"} print;END{print "last\n"}' $File > NewFile
    

    这与上面用 Perl 编写的 gawk 本质上是一样的。

答案4

您可以在 Ex 模式下使用 Vim:

ex -sc '1i|ALFA' -c '$a|BRAVO' -cx file
  1. 1选择第一行

  2. i插入文本和换行符

  3. $选择最后一行

  4. a追加文本和换行符

  5. x保存并关闭

相关内容