如何删除文件中少于 6 个字符的所有行?

Tel*_*Why 18 command-line text-processing

我有一个包含大约 1000 万行的文件。

我想删除文件中少于六个字符的所有行。

我该怎么做呢?

hee*_*ayl 31

有很多方法可以做到这一点。

使用grep

grep -E '^.{6,}$' file.txt >out.txt
Run Code Online (Sandbox Code Playgroud)

现在out.txt将包含具有六个或更多字符的行。

反转方式:

grep -vE '^.{,5}$' file.txt >out.txt
Run Code Online (Sandbox Code Playgroud)

使用sed,删除长度为 5 或更短的行:

sed -r '/^.{,5}$/d' file.txt
Run Code Online (Sandbox Code Playgroud)

反向方式,打印长度为 6 行或更多的行:

sed -nr '/^.{6,}$/p' file.txt 
Run Code Online (Sandbox Code Playgroud)

您可以使用>操作符将输出保存在不同的文件中,grep或者使用以下-i选项就地编辑文件sed

sed -ri.bak '/^.{6,}$/' file.txt 
Run Code Online (Sandbox Code Playgroud)

原始文件将被备份file.txt.bak和修改后的文件会file.txt

如果您不想保留备份:

sed -ri '/^.{6,}$/' file.txt
Run Code Online (Sandbox Code Playgroud)

使用 shell, Slower, Don't do this,这只是为了展示另一种方法:

grep -E '^.{6,}$' file.txt >out.txt
Run Code Online (Sandbox Code Playgroud)

使用python, 甚至比grep, 还慢sed

grep -vE '^.{,5}$' file.txt >out.txt
Run Code Online (Sandbox Code Playgroud)

更好地使用列表理解来更 Pythonic:

sed -r '/^.{,5}$/d' file.txt
Run Code Online (Sandbox Code Playgroud)

  • 另外,当使用第一个选项时,@DevRobot 不太确定 python 在处理大文件时速度较慢。实际上,我很确定 python 在数百万行上速度更快,因为它每行读取一次。 (2认同)
  • 第二个 python 示例在执行连接之前将整个文件读入内存。我认为第一个 python 示例在这种情况下更好。 (2认同)

Oli*_*lac 19

这很简单:

grep ...... inputfile > resultfile   #There are 6 dots
Run Code Online (Sandbox Code Playgroud)

这是非常有效的,因为grep不会尝试解析超过需要,也没有解释字符以任何方式:它只需发送一个(整体)线到标准输出(其中壳,然后重定向到resultfile)尽快为它看到6该行上的字符(.在正则表达式上下文中匹配任何 1 个字符)。

因此,grep 只会输出具有 6 个(或更多)字符的行,而其他行则不会由 grep 输出,因此它们不会进入结果文件。


kos*_*kos 14

解决方案#1:使用C

最快的方法:编译并运行这个 C 程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUFFER_SIZE 1000000

int main(int argc, char *argv[]) {
    int length;

    if(argc == 3)
        length = atoi(argv[2]);
    else
        return 1;

    FILE *file = fopen(argv[1], "r");

    if(file != NULL) {
        char line[MAX_BUFFER_SIZE];

        while(fgets(line, sizeof line, file) != NULL) {
            char *pos;

            if((pos = strchr(line, '\n')) != NULL)
                *pos = '\0';
            if(strlen(line) >= length)
                printf("%s\n", line);
        }

        fclose(file);
    }
    else {
        perror(argv[1]);
        return 1;
    }
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译gcc program.c -o program,运行./program file line_length(其中file= 文件路径和line_length= 最小行长度,在您的情况下6;最大行长度限制为1000000每行字符;您可以通过更改 的值来更改此设置MAX_BUFFER_SIZE)。

\n\0found here代替的技巧。)

除了 shell 解决方案之外,与针对此问题提出的所有其他解决方案进行比较(测试运行在 1000 万行、平均长度为 8 个字符的 ~91MB 文件上):

time ./foo file 6

real    0m1.592s
user    0m0.712s
sys 0m0.160s

time grep ...... file

real    0m1.945s
user    0m0.912s
sys 0m0.176s

time grep -E '^.{6,}$'

real    0m2.178s
user    0m1.124s
sys 0m0.152s

time awk 'length>=6' file

real    0m2.261s
user    0m1.228s
sys 0m0.160s

time perl -lne 'length>=6&&print' file

real    0m4.252s
user    0m3.220s
sys 0m0.164s

sed -r '/^.{,5}$/d' file >out

real    0m7.947s
user    0m7.064s
sys 0m0.120s

./script.py >out
real    0m8.154s
user    0m7.184s
sys 0m0.164s
Run Code Online (Sandbox Code Playgroud)

解决方案#2:使用AWK:

awk 'length>=6' file
Run Code Online (Sandbox Code Playgroud)
  • length>=6: 如果length>=6返回 TRUE,则打印当前记录。

解决方案 #3:使用 Perl:

perl -lne 'length>=6&&print' file
Run Code Online (Sandbox Code Playgroud)
  • 如果lenght>=6返回 TRUE,则打印当前记录。

% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file   
ffffff
ggggggg
% perl -lne 'length>=6&&print' file
ffffff
ggggggg
Run Code Online (Sandbox Code Playgroud)

  • 相信我..我正在等待_your_ `awk` 解决方案.. (2认同)
  • @heemayl 而且我没有立即看到这个问题,所以我*知道*如果你碰巧在线,你会更快。不得不删除我的 `sed` 解决方案(它发生了,我知道)。XD (2认同)
  • @tripleee这个想法是添加一个解决方案,它不仅适用于一次性工作,甚至适用于更大的文件,*但是*:我在同一个文件上测试了“grep”解决方案,它实际上更快(可能是因为“strlen”) ()` 在这里不是最好的主意)。我将尝试使用 `getchar()` 循环来仅检查前 N 个字符,我想这应该会明显改善它。是的,任何超过缓冲区长度的行都会被简单地剪切到缓冲区的长度。 (2认同)