如何删除文本文件中长度大于 1GB 的所有行?

How to delete all lines bigger than 1GB in length in a text file?

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

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

bash 中的天真解决方案会执行后者并且可能会崩溃:

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

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


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

#!/bin/bash

max=1000000000
buflen=33554432

len=0
data="$(tempfile)"

savedata(){
    printf "%s" "" >>"$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
  • -i 就地更改 file
  • -n 在程序周围包裹了一个隐式迭代行循环
  • 1e9 是 1000000000
  • 的缩写形式
  • say 就像 bash 的 echo

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

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