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


Answers:


30

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

使用grep

grep -E '^.{6,}$' file.txt >out.txt

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

反向方式:

grep -vE '^.{,5}$' file.txt >out.txt

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

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

相反,打印长度为六或更多的行:

sed -nr '/^.{6,}$/p' file.txt 

您可以使用>类似类似的运算符将输出保存到其他文件中,grep或使用以下-i选项就地编辑文件sed

sed -ri.bak '/^.{6,}$/' file.txt 

原始文件将备份为file.txt.bak,修改后的文件将备份为file.txt

如果您不想保留备份:

sed -ri '/^.{6,}$/' file.txt

使用shell,Slower,不要这样做,这只是为了显示另一个方法:

while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt

使用python,甚至慢于grepsed

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        if len(line.rstrip('\n')) >= 6:
            print line.rstrip('\n')

更好地使用列表理解功能以增强Python风格:

#!/usr/bin/env python2
with open('file.txt') as f:
     strip = str.rstrip
     print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')

好极了!我希望得到一个python答案=)
TellMeWhy

@DevRobot我明白了..
然后

1
同样,@DevRobot不能确定使用第一个选项时,在大型文件上python的运行速度较慢。实际上,我很确定python在数百万行上速度更快,因为它每行读取一次。
Jacob Vlijm '16

1
第二个python示例在进行连接之前将整个文件读入内存。我认为第一个python示例在这种情况下更好。
Holloway

按行读取必然较慢,因为文件的结构并非如此。无论如何,您都需要提前阅读一个程序块并搜索具有减少并行化可能性的换行符,然后仅返回部分字符串。您需要一个循环缓冲区。如果您不知道行的长度,则需要动态分配内存。
Vee

19

很简单:

grep ...... inputfile > resultfile   #There are 6 dots

这非常高效,因为它grep不会尝试解析超出其所需的内容,也不会以任何方式解释字符:它只是在看到6时立即向stdout发送了(整个)行(shell然后将其重定向到resultfile)。该行上的字符(.在regexp上下文中匹配任何1个字符)。

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


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;
}

编译为gcc program.c -o program,运行方式为./program file line_length(其中,file=文件路径,line_length=最小行长6;最大行长限于1000000每行字符;您可以通过更改的值来更改MAX_BUFFER_SIZE)。

(伎俩替代\n\0发现在这里。)

与针对此问题的所有其他解决方案(shell解决方案)进行比较(测试运行在〜91MB的文件上,该文件具有10M行,平均长度为8个字符):

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

解决方案2:使用AWK:

awk 'length>=6' file
  • length>=6:如果length>=6返回TRUE,则打印当前记录。

解决方案#3:使用Perl:

perl -lne 'length>=6&&print' file
  • 如果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

1
相信我.. 我正在等待您的 awk解决方案..
heemayl 2016年

2
@heemayl而且我没有立即看到问题,所以我知道,如果您碰巧在线,那么您会更快。必须删除我的sed解决方案(我知道发生了)。XD
kos

pos变量的意义是什么?我得到它返回一个line带有换行符的字符指针,但是您似乎从未使用过它。如果找不到它,只需将其设置为即可\0
user1717828

@ user1717828如果找到它,我将其替换为\0strchr()如果找到该字符,返回NULL指针)。关键是用每行的末尾替换每个换行符,以\0使该换行符永远不会被计算在内strlen():这样一来,总长度就可以始终与6进行比较,而不考虑最后一行可能缺少的换行符。我知道,仅对最后一行进行不同的处理会更有效率。我可能稍后再更新。
kos

1
@tripleee这个想法是要添加一个解决方案,该解决方案不仅可以用于一次性工作,甚至可以用于更大的文件,但是:我grep在同一个文件上测试了该解决方案,而且速度实际上更快(可能strlen()不是这里的最佳主意) 。我将尝试使用getchar()循环以仅检查第一个N字符,我认为应该明显改善它。是的,只要将缓冲区长度上的任何行剪切为缓冲区的长度即可。
kos

2

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

ex -sc 'v/\v.{6}/d' -cx file
  1. \v 打开魔术

  2. .{6} 查找具有6个或更多字符的行

  3. v 反转选择

  4. d 删除

  5. x 保存并关闭


1

Ruby解决方案:

$ cat input.txt                                                                                                          
abcdef
abc
abcdefghijk

$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt                                                              
abcdef
abcdefghijk

简单的想法:将文件重定向到ruby的stdin,并且仅在其长度大于或等于6时才从stdin打印行

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.