我收到的数据将在130GB-300GB的范围内,其中在单个文件夹中包含1000个(也许是数百万个)小型.txt
文件,大小为2KB-1MB。我想高效地解析它们。
我正在查看以下选项(引自-21209029]:
使用printf
+ xargs
(随后是egrep
和awk
文本处理)
printf '%s\0' *.txt | xargs -0 cat | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' > all_in_1.out
使用find
+ cat
(随后是egrep
和awk
文本处理)
find . -name \*.txt -exec cat {} > all_in_1.tmp \;
cat all_in_1.tmp | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' > all_in_1.out
使用for
循环
for file in *.txt
do
cat "$file" | egrep -i -v 'pattern1|...|pattern8' | awk '{gsub(/"\t",",")}1' >> all_in_1.out
done
以上哪一项是最有效的?有更好的方法吗?
还是完全不建议使用shell命令来处理这种数量的数据处理(我确实更喜欢使用shell方法)?
服务器具有RHEL 6.5 OS,具有32 GB内存和16核(@ 2.2GHz)。
答案 0 :(得分:1)
方法1和3在Shell命令行上展开文件列表。这不适用于大量文件。如果文件分布在许多目录中(可能包含数百万个文件),则方法1和3也不起作用。
方法2复制所有数据,因此效率也不高。
您应该使用find
并将文件名直接传递到egrep
。使用-h
选项可取消显示文件名前缀:
find . -name \*.txt -print0 \
| xargs -0 egrep -i -v -h 'pattern1|...|pattern8' \
| awk '{gsub(/"\t",",")}1' > all_in_1.out
xargs
将自动依次顺序启动多个egrep
进程,以避免在一次调用中超出命令行限制。
根据文件内容,完全避免egrep
进程,而直接在awk
中进行过滤也可能更有效:
find . -name \*.txt -print0 \
| xargs -0 awk 'BEGIN { IGNORECASE = 1 } ! /pattern1|...|pattern8/ {gsub(/"\t",",")}1' > all_in_1.out
BEGIN { IGNORECASE = 1 }
对应于-i
的{{1}}选项,并且egrep
颠倒了匹配的意义,就像!
一样。 -v
似乎是GNU扩展名。