首页 > 解决方案 > 如何删除文本文件中长度大于 1GB 的所有行?

问题描述

我有一个可能包含长行的文本文件。如何删除该文件中长度超过 1GB 的所有行,只保留小于 1GB 的行?谢谢

标签: bashline

解决方案


我相信您的问题的任何解决方案都需要多次读取文件或将行读取到至少 1GB 大的缓冲区中。

bash 中的一个幼稚的解决方案是后者,并且可能会崩溃:

#!/bin/bash
while IFS= read -r line; do
    if [ ${#line} -le 1000000000 ]; then
        echo "$line"
    fi
done <infile >tmpfile
mv tmpfile infile

它会运行得非常慢,从快速测试来看,我认为它需要的内存是最长线路的 3 倍。


我们可以读入一个较小的缓冲区来避免这种情况,但代码要复杂得多,而且运行速度仍然非常慢。例如:

#!/bin/bash

max=1000000000
buflen=33554432

len=0
data="$(tempfile)"

savedata(){
    printf "%s" "$1" >>"$data"
    (( len+=${#1} ))
}

cleardata(){
    cat /dev/null >"$data"
    len=0
}

maybeprintdata(){
    if (( len<max )); then
        cat "$data"
        (( noecho )) || echo
    fi
}

(
    while IFS= read -n $buflen -r line || [ -n "$line" ]; do
        savedata "$line"
        if (( ${#line}!=buflen )); then
            maybeprintdata
            cleardata
        fi
    done 
    (( len )) && noecho=1 maybeprintdata

) <infile >tmpfile
mv tmpfile infile

rm "$data"

如果您不限于 bash,则可以使用更快的程序。

与朴素 bash 解决方案等效的“单线”Perl 可能是:

perl -i -nlE 'length>1e9 || say' file
  • -ifile就地进行更改
  • -n在程序周围包装一个隐式迭代行循环
  • 1e9是 1000000000 的简写形式
  • say就像bash的echo

请注意,与上面“复杂”的 bash 程序不同,这个简单的 Perl 程序会输出最后一个换行符,即使输入没有换行符。

另请注意,它需要与最长文件行一样多的 RAM(如果行长可能超过内存,这可能是一个问题)。


推荐阅读