命令输出redirect

给定一个包含几百万个文件的目录,我们希望从这些文件中提取一些数据。

find /dir/ -type f | awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' > the_good_stuff.txt

这将永远不会缩放,所以我们引入xargs。

find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }'

无论我们运行多长时间,这都会产生有效的输出。 Sweet可以通过在该命令上附加一个> the_good_stuff_from_xargs.txt来将它写入文件。 除了现在文件包含损坏的行。

令我震惊的是,在查看xargs在terminal中作为STDOUT打开的六个subprocess的输出时,数据看起来很好。 数据redirect文件系统的时刻是出现损坏的时刻。

我试图追加下面的命令。

> myfile.txt

>> myfile.txt

| mawk '{print $0}' > myfile.txt

还有其他一些redirect的概念,或者在将xargs的输出“写入”磁盘之前将其汇集到每个版本中数据被破坏的磁盘上。

我是积极的原始文件不格式化。 我认为,当在terminal作为标准输出查看命令与xargs产生有效的输出,长达10分钟的盯着它吐文本…

本地磁盘是SSD …我正在读取和写入相同的文件系统。

为什么redirectfind /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' find /dir/ -type f -print0 | xargs -0 -n1 -P6 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }'会导致数据变得格式不正确?

编辑

我目前不能安装unbuffer,但stdbuf -oL -eL会修改命令输出为行缓冲,所以理论上应该做同样的事情。

我试过stdbuf xargs cmdxargs stdbuf cmd都导致了非常破碎的行。

需要-P6才能在任何合理的时间内完成该命令。

编辑2

澄清… xargs-P6标志是解决问题的要求,因为我们工作的目录中有数百万个必须扫描的文件。

很明显,我们可以删除-P6或以其他方式同时停止运行多个工作,但是这并不能真正回答为什么输出会受到损坏的问题,也不能真正地解决输出如何恢复到“正确“同时还在大规模完成任务。

接受的答案提到使用parallel ,在所有的答案中最好的工作。

我跑的最后一个命令看起来像。 time find -L /dir/ -type f -mtime -30 -print0 | parallel -0 -X awk -f manual.awk > the_good_stuff.txt time find -L /dir/ -type f -mtime -30 -print0 | parallel -0 -X awk -f manual.awk > the_good_stuff.txt awk很困难,所以我把-F"|" 进入命令本身。 默认情况下,并行会为每个核心启动一个作业,如果需要,可以使用-j来设置较低的作业数量。

用科学术语来说,这是一个巨大的提速。 在6分钟之后,没有测量的小时数(可能是6+)是10%完成的,所以可能在一个小时内完成。

一个问题是,您必须确保parallel运行的命令不会尝试写入文件…,这样可以有效地绕过并行执行的输出处理。

最后没有-X平行的行为类似于xargs -n1

man xargs提到这个问题:“请注意,这是由被调用的进程来正确管理对共享资源的并行访问,例如,如果他们中有不止一个人试图打印到stdout,则会以不确定的顺序(很可能混在一起)“

幸运的是,有一种方法可以使这个操作快一个数量级,同时也解决了这个问题:

 find /dir/ -type f -print0 | xargs -0 awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' 

为什么?

-P6正在洗牌您的输出,所以不要使用它。 xargs -n1为每个文件启动一个awk进程,而没有n1xargs启动很少的awk进程,如下所示:

 files | xargs -n1 awk => awk file1 awk file2 ... awk fileN vs files | xargs awk => awk file1 file2 ... fileN # or broken into a few awk commands if many files 

我运行你的代码约20K的文本文件,每个-n1 -P6大小有和没有-n1 -P6

 with -n1 -P6 23.138s without 3.356s 

如果你想要没有xargs的标准输出的parallel ,可以使用gnu parallel (也可以用Gordon Davisson的建议),例如:

 find /dir/ -type f -print0 | parallel --xargs -0 -q awk -F"|" '$2 ~ /string/{ print $3"|"$7 }' 

注意: -q是引用命令字符串所必需的,否则引号在-F"|"awk代码在parallel运行时不会被引用。

parallel节省了一点时间,但不像开沟一样 – -n1

 parallel 1.704s 

ps:介绍一只cat (Matt在他的回答中)比xargs awk快得多:

 xargs awk 3.356s xargs cat | awk 3.036s 

我只会做以下几点:

 cat /${dir}/* | awk '$2 ~ /string*/{ print $3 "|" $7 }' >> `date`.txt 

文件以运行进程的日期和时间命名。