【问题标题】:Reorder lines near the beginning of a huge text file (>20G)对大文本文件(>20G)开头附近的行重新排序
【发布时间】:2026-01-18 17:20:05
【问题描述】:

我是 vim 用户,可以使用一些基本的 awk 或 bash 命令。现在我有一个大小超过 20G 的文本 (vcf) 文件。我想要的是将第 69 行移到第 66 行下方:

$less huge.vcf
...
    66 ##contig=<ID=9,length=124595110>                                                                                                                                                       
    67 ##contig=<ID=X,length=171031299>                                                                                                                                                       
    68 ##contig=<ID=Y,length=91744698>                                                                                                                                                        
    69 ##contig=<ID=MT,length=16299>
...

我想要的是:

...
    66 ##contig=<ID=9,length=124595110>     
    67 ##contig=<ID=MT,length=16299>                                                                                                                                                  
    68 ##contig=<ID=X,length=171031299>                                                                                                                                                       
    69 ##contig=<ID=Y,length=91744698>                                                                                                                                                        
...

我尝试使用 vim(安装了大文件插件)打开和编辑它,但仍然不能很好地工作。

【问题讨论】:

  • 只是在文件的一小部分内移动内容,而不改变该部分的长度?这很好——意味着你实际上可以有效地做到这一点!
  • (相比之下,在大文件的开头添加新内容或以修改整个文件长度的方式删除内容只有在修改发生的位置之后重写整个文件时才有可能,如果您仅限于标准 UNIX 系统调用。现代 Linux 有一些扩展,可让您在使用具有适当扩展名的文件系统时在确切的块/页面边界处插入和删除与块/页面大小匹配的部分(通常为 4kb 块),但是这通常只是有限的用途)。
  • vim 的部分问题是它试图在编辑后重新计算行号。我懒得创建一个 20GB 的文件,但是使用像 :69m66 这样的 ex 命令可能会有所帮助。

标签: bash vim dd


【解决方案1】:

简单的方法是将要编辑的部分从文件中复制出来,就地修改,然后再复制回来。

# extract the first hundred lines
head -n 100 huge.txt >start.txt

# modify that extracted subset
vim start.txt

# copy that section back into the beginning of larger file
dd if=start.txt of=huge.txt conv=notrunc

请注意,这仅适用于您的编辑不会更改正在修改的部分的大小。也就是说——确保start.txt在修改后的字节大小与之前完全相同。

【讨论】:

    【解决方案2】:

    这是一个 awk 版本:

    $ awk 'NR>=3 && NR<=4{b=b (b==""?"":ORS) $0;next}1;NR==5 {print b}' file
    ...
        66 ##contig=<ID=9,length=124595110>
        69 ##contig=<ID=MT,length=16299>
        67 ##contig=<ID=X,length=171031299>
        68 ##contig=<ID=Y,length=91744698>
    ...
    

    不过,您需要更改代码中的行号。 3 -&gt; 67, 4 -&gt; 685 -&gt; 69 并将输出重定向到新文件。如果您喜欢它就地执行,请使用i inplace 来表示 GNU awk。

    【讨论】:

    • 我看不到这会执行就地编辑,更不用说高效了。我错过了什么?
    • ...啊。当我读到它时,OP 不 想要 创建一个新文件。他们想要编辑现有的 20GB 文件,并使其快速(即不重写整个 20GB)。
    • 好吧,这样不行。