Answers:
有很多方法可以做到这一点。
使用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
,甚至慢于grep
,sed
:
#!/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')
很简单:
grep ...... inputfile > resultfile #There are 6 dots
这非常高效,因为它grep
不会尝试解析超出其所需的内容,也不会以任何方式解释字符:它只是在看到6时立即向stdout发送了(整个)行(shell然后将其重定向到resultfile)。该行上的字符(.
在regexp上下文中匹配任何1个字符)。
因此,grep将仅输出具有6个(或更多)字符的行,而grep不会输出其他字符,因此它们不会进入结果文件。
最快的方法:编译并运行此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
awk 'length>=6' file
length>=6
:如果length>=6
返回TRUE,则打印当前记录。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
awk
解决方案..
sed
解决方案(我知道发生了)。XD
pos
变量的意义是什么?我得到它返回一个line
带有换行符的字符指针,但是您似乎从未使用过它。如果找不到它,只需将其设置为即可\0
。
\0
(strchr()
如果未找到该字符,则返回NULL指针)。关键是用每行的末尾替换每个换行符,以\0
使该换行符永远不会被计算在内strlen()
:这样一来,总长度就可以始终与6进行比较,而不考虑最后一行可能缺少的换行符。我知道,仅对最后一行进行不同的处理会更有效率。我可能稍后再更新。
grep
在同一个文件上测试了该解决方案,而且速度实际上更快(可能strlen()
不是这里的最佳主意) 。我将尝试使用getchar()
循环以仅检查第一个N字符,我认为应该明显改善它。是的,只要将缓冲区长度上的任何行剪切为缓冲区的长度即可。
Ruby解决方案:
$ cat input.txt
abcdef
abc
abcdefghijk
$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt
abcdef
abcdefghijk
简单的想法:将文件重定向到ruby的stdin,并且仅在其长度大于或等于6时才从stdin打印行