为什么并行模式下的 xargs 不能与 grep 一起使用?

Why doesn't xargs in parallel mode work with grep?

cat gg

给予

192

cat tmpfilelist

给予

android/app/src/main/res/drawable-mdpi/src_assets_images_alerts_iconnotificationsmartpluggreen.png
android/app/src/main/res/drawable-mdpi/src_assets_images_ic_biggames.png  
android/app/src/main/res/drawable-xhdpi/src_assets_images_alerts_iconnotificationsmartpluggreen.png  
android/app/src/main/res/drawable-xhdpi/src_assets_images_ic_biggames.png   
android/app/src/main/res/drawable-xxhdpi  /src_assets_images_alerts_iconnotificationsmartpluggreen.png  
android/app/src/main/res/drawable-xxhdpi/src_assets_images_ic_biggames.png  
gg  
ios/WebRTC.framework/Headers/RTCCallbackLogger.h  
ios/WebRTC.framework/Headers/RTCFileLogger.h  
ios/WebRTC.framework/Headers/RTCLogging.h  

I 运行 xargs 并联模式打开 - 这找不到所需的文本“192”:

cat tmpfilelist | \xargs   -P0 -t  -I {} \bash  -c "\grep -C 2 -H -I -r 192 {}" |& \grep -C 3 "192 gg"
bash -c '\grep -C 2 -H -I -r 192 android/app/src/main/res/drawable-xhdpi/src_assets_images_ic_biggames.png'  
bash -c '\grep -C 2 -H -I -r 192 android/app/src/main/res/drawable-xxhdpi/src_assets_images_alerts_iconnotificationsmartpluggreen.png'  
bash -c '\grep -C 2 -H -I -r 192 android/app/src/main/res/drawable-xxhdp/src_assets_images_ic_biggames.png'  
bash -c '\grep -C 2 -H -I -r 192 gg'
bash -c '\grep -C 2 -H -I -r 192 ios/WebRTC.framework/Headers/RTCCallbackLogger.h'  
bash -c '\grep -C 2 -H -I -r 192 ios/WebRTC.framework/Headers/RTCFileLogger.h'  
bash -c '\grep -C 2 -H -I -r 192 ios/WebRTC.framework/Headers/RTCLogging.h'  

当我禁用并行模式时,它成功地在文件 "gg":

中找到文本“192”
cat tmpfilelist | \xargs   -t  -I {} \bash  -c "\grep -C 2 -H -I -r 192 {}" |& \grep -C 3 "192 gg"
bash -c '\grep -C 2 -H -I -r 192 android/app/src/main/res/drawable-xhdpi/src_assets_images_ic_biggames.png'  
bash -c '\grep -C 2 -H -I -r 192 android/app/src/main/res/drawable-xxhdpi/src_assets_images_alerts_iconnotificationsmartpluggreen.png'  
bash -c '\grep -C 2 -H -I -r 192 android/app/src/main/res/drawable-xxhdp/src_assets_images_ic_biggames.png'  
bash -c '\grep -C 2 -H -I -r 192 gg'  
gg:192  
bash -c '\grep -C 2 -H -I -r 192 ios/WebRTC.framework/Headers/RTCCallbackLogger.h'  
bash -c '\grep -C 2 -H -I -r 192 ios/WebRTC.framework/Headers/RTCFileLogger.h'  

为什么并行模式会破坏 grep?还是我哪里弄错了?

非常感谢

确实是并行执行的问题。问题是当您 运行 并行输出时,输出不确定。我创建了一个类似的测试

bash-5.0# ls -alh
total 32K
drwxr-xr-x    9 root     root         288 May 20 17:00 .
drwxr-xr-x    1 root     root        4.0K May 20 17:11 ..
-rw-r--r--    1 root     root           3 May 20 17:00 a
-rw-r--r--    1 root     root           3 May 20 17:00 b
-rw-r--r--    1 root     root           3 May 20 17:00 c
-rw-r--r--    1 root     root           4 May 20 17:00 d
-rw-r--r--    1 root     root           3 May 20 17:00 e
-rw-r--r--    1 root     root           3 May 20 17:00 f
-rw-r--r--    1 root     root          11 May 20 17:00 files

bash-5.0# tail -n +1 *
==> a <==
192
==> b <==
193
==> c <==
192
==> d <==
195

==> e <==
200
==> f <==
198
==> files <==
a
b
c
d
e
f

现在,如果我们 运行 你的两个命令没有最后一个 grep,输出如下所示

不并联

bash-5.0# cat files | \xargs   -t  -I {} \bash  -c "\grep -C 2 -H -I -r 192 {}"
bash -c \grep -C 2 -H -I -r 192 a
a:192
bash -c \grep -C 2 -H -I -r 192 b
bash -c \grep -C 2 -H -I -r 192 c
c:192
bash -c \grep -C 2 -H -I -r 192 d
bash -c \grep -C 2 -H -I -r 192 e
bash -c \grep -C 2 -H -I -r 192 f

并联

bash-5.0# cat files | \xargs  -P4 -t  -I {} \bash  -c "\grep -C 2 -H -I -r 192 {}"
bash -c \grep -C 2 -H -I -r 192 a
bash -c \grep -C 2 -H -I -r 192 b
bash -c \grep -C 2 -H -I -r 192 c
bash -c \grep -C 2 -H -I -r 192 d
bash -c \grep -C 2 -H -I -r 192 e
a:192
bash -c \grep -C 2 -H -I -r 192 f
c:192

希望您能看到它是如何影响您生产线的输出和订单的。所以你的问题是,当你执行 grep -C 3 192 gg 时,你应该在打印 192 gg 之前得到 3 行,在打印之后得到 3 行,你实际上得到了。

但是 gg:192 稍后打印,因为每个命令在同一个输出终端上并行发送它们的输出

不是答案 - 但指出了可能的问题。

代码在管道中运行两个过滤器

  • grep -C 2 -H -I -r 192 文件名
  • grep -C 3 "192 gg"

第一行的输出将遵循 'FILENAME:DATA' 格式。在上面的例子中

gg:192

第二个过滤器不会找到模式“192 gg”。

所以问题可能是非并行如何产生任何输出?

简答

您的最终 grep -C 3 请求围绕 192 gg 的 3 行上下文。在并行情况下,这可能不足以找到包含 gg:192.

的行

详情

在最后的 grep 之前,您的输出将包含许多行,例如:

bash -c \grep -C 2 -H -I -r 192 <filename>

xargs 启动每个 bash -c ... 命令之前回显到 stderr,行

gg:192
当相关 bash -c ... 命令(即涉及文件 gg 的命令)找到匹配项时,

被回显到标准输出。

在并行情况下,通过管道传输到最终 grep 的整个输出(一旦使用 |& 组合了 stderr 和 stdout)可能看起来像这样,我已经替换了为简洁起见的其他文件名:

bash -c \grep -C 2 -H -I -r 192 some_file
bash -c \grep -C 2 -H -I -r 192 some_other_file
bash -c \grep -C 2 -H -I -r 192 another_file
bash -c \grep -C 2 -H -I -r 192 gg
bash -c \grep -C 2 -H -I -r 192 and_another_file
bash -c \grep -C 2 -H -I -r 192 yet_another_file
gg:192
bash -c \grep -C 2 -H -I -r 192 and_yet_another_file

在此示例中,涉及 and_another_fileyet_another_filebash -c ... 命令被启动 涉及 gg 的命令之后已启动,但在涉及 gg 的那个写入其输出之前(或至少在刷新与该输出关联的任何 stdio 缓冲区之前),因此它们出现在包含 192 gggg:192 的行之间.

包含 192 gggg:192 的行之间的此类中间行的数量(在本例中为 2)将取决于时间和在该任务之后启动的其他并行任务的数量涉及 gg。这会有所不同,例如,如果您插入了 sleep 语句(例如 ... \bash -c "sleep 1; \grep -C ...),那么往往会有更多这样的行。在任何情况下,您都将其通过管道传输到 grep -C 3 以提取 3 行上下文。如果恰好有少于 3 个中间行,那么这个 grep -C 将找到包含 gg:192 的行,但如果有 3 个或更多,那么它将超出请求的上下文量并且不会出现在最终输出中。

然而,在串行情况下,gg:192 行保证始终紧跟在 192 gg 行之后,如下所示:

bash -c \grep -C 2 -H -I -r 192 some_file
bash -c \grep -C 2 -H -I -r 192 some_other_file
bash -c \grep -C 2 -H -I -r 192 another_file
bash -c \grep -C 2 -H -I -r 192 gg
gg:192
bash -c \grep -C 2 -H -I -r 192 and_another_file
bash -c \grep -C 2 -H -I -r 192 yet_another_file
bash -c \grep -C 2 -H -I -r 192 and_yet_another_file

所以它总是在 3 行上下文中。