我正在学习一点重击通过使用参数列出一堆 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 3
到xargs
.
-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 {} \+