由于 xargs 的原因,输出会像这样混合吗?我该如何修复它?

由于 xargs 的原因,输出会像这样混合吗?我该如何修复它?

我正在学习一点重击通过使用参数列出一堆 IP 地址的 whois 记录。使用的命令是:

echo "$1" | tr "\n" "\0" | xargs -0 -n 1 -t -P 3 -I %  sh -c 'echo "\n 44rBegin whois record -- \n"; whois -h whois.arin.net % ; echo "\n 44rEnd whois record -- \n"'

执行的命令是:

sh -c echo "\n 44rBegin whois record -- \n"; whois -h whois.arin.net 206.190.36.45 ; echo "\n 44rEnd whois record -- \n"
sh -c echo "\n 44rBegin whois record -- \n"; whois -h whois.arin.net 212.146.69.237 ; echo "\n 44rEnd whois record -- \n"
sh -c echo "\n 44rBegin whois record -- \n"; whois -h whois.arin.net 77.238.184.24 ; echo "\n 44rEnd whois record -- \n"

我希望输出看起来好像使用执行的每个命令块sh -c都是按顺序执行的。相反,我的输出是这样的:

44rBegin whois record

44rBegin whois record

44rBegin whois record

whois1 output

44rEnd whois record --

whois2 output

44rEnd whois record --

whois3 output

44rEnd whois record --

我该如何解决这个问题?

答案1

在这种特定情况下,您将传递-P 3xargs.

   -P max-procs
          Run up to max-procs processes at a time; the default is 1.  If max-procs  is
          0,  xargs  will run as many processes as possible at a time.  Use the -n op‐
          tion with -P; otherwise chances are that only one exec will be done.

因为您并行运行它们,所以它们都会同时写入输出。

如果您从其他地方复制了此命令,我建议您进行研究以了解您正在复制的内容。否则可能会很危险。

答案2

任何时候你有多个进程并行输出到同一个终端(或文件),你就会面临它们的输出分散的风险(除非你安排进行某种锁定或使用低级系统调用,例如write附加打开的文件) -仅模式)。

作为第一步,您可以通过让每个 shell 调用使用命令替换:将whois命令作为子进程运行,捕获其输出,然后将所有内容组合到一个printf操作中。

xargs -0 -n 1 -P 3 -I %% sh -c 'printf "\n%s\n%s\n%s\n" " 44rBegin whois record -- " "$(whois -h whois.arin.net %%)" " 44rEnd whois record -- "'

更好的是,如果您有flock可用的程序,您可以使用它来锁定对该组合的每个调用printf

xargs -0 -n 1 -P 3 -I %% sh -c 'who="$(whois -h whois.arin.net %%)"; flock /tmp/who.lock printf "\n%s\n%s\n%s\n" " 44rBegin whois record -- " "$who" " 44rEnd whois record -- "'

答案3

是的,由于 ,输出是混合的xargs -P。您正在并行执行多个子进程,并且没有任何东西可以协调它们的输出:它们都在想要的时候写入输出,并且所有这些都混合在一起。

使用GNU 并行,这是一个更强大的工具,可以完成与 相同的工作xargs -P。它的默认值是将每个作业的输出分组在一起

echo "$1" | parallel -t -P 3 sh -c 'echo "\n 44rBegin whois record -- \n"; whois -h whois.arin.net $0; echo "\n 44rEnd whois record -- \n"'

答案4

我该如何解决这个问题?

cat将标准输出重定向到每个进程以及稍后所有进程的文件,以演示此技术:

seq 100 | sort -R |
  xargs -I@ -P0 sh -c '{ echo begin @ && sleep 0.@ && echo end @; } > $$.log' &&
  find . -name '*.log' -exec cat {} \+

将此技术应用到您的命令中:

echo "$1" |
  tr "\n" "\0" |
  xargs -0 -n 1 -t -P 3 -I % sh -c '{echo "\n 44rBegin whois record -- \n"; whois -h whois.arin.net % ; echo "\n 44rEnd whois record -- \n";} > $$.log' &&
  find . -name '*.log' -exec cat {} \+

相关内容