删除除 D 之外的所有行

删除除 D 之外的所有行

我有一个场景,其中有我的三个大文件Test.txtTest1.txt并且Test2.txt有以下详细信息。

H|||||||||||||||||||||||
D||||||||||||||||||||||||
D|||||||||||||||||||||||
H|||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||
T||||||||||||||||||||||||

我必须删除除 D 行之外的所有内容。在我的所有三个文件中,它应该如下所示。(超过 10 GB)

D||||||||||||||||||||||||
D|||||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||

Test.txt因此,在仅保留、Test2.txt和中的 D 行后Test3.txt,我必须将它们合并到新文件中。

我已经使用 sed 完成了上述操作。

sed '/^\('D'\)|/!d' $Filename.txt >>  $NewFilename.txt

但由于文件巨大,需要很长时间。

我们可以使用任何其他命令以有效的方式完成此操作吗?

答案1

cat Test.txt Test2.txt Test3.txt | LC_ALL=C grep '^D' > newfile.txt

或者:

for file in Test.txt Test2.txt Test3.txt; do
  LC_ALL=C grep '^D' < "$file"
done > newfile.txt

或者,如果您grep喜欢的 GNUgrep支持该-h选项(以避免打印文件名):

LC_ALL=C grep -h '^D' Test.txt Test2.txt Test3.txt > newfile.txt

通过使用LC_ALL=C我们可以避免grep尝试解析 UTF-8 数据。通过使用^Dgrep将仅查看每行的第一个字符。grep,尤其grep是 GNU 通常比sed.

答案2

这很可能是 I/O 绑定操作(而不是 CPU 绑定),因此即使您不使用如下的正则表达式引擎:

grep -F 'D|' Test.txt Test2.txt Test3.txt

这将需要很长时间,因为文件必须被标记为行,然后扫描模式。

如果这是一次性的事情并且您不介意编码,您可以将mmap(3)整个文件放入内存并使用memmem(3)

char *p;
if ((p = memmem(file, size, "\nD|", 3)) != NULL) {
        /* massage the line, i.e. find the next '\n'
         * and print the region between p+1 and the
         * next '\n' */
}

其中file是指向映射缓冲区的指针,size是文件大小。 (如果这有帮助,我很乐意详细说明)。

这种方法仍然需要一些时间(因为您的问题是 I/O 限制),但至少您可以节省将文件标记为行的时间。

相关内容