xargs:在并行模式下将标准输出重定向到文件时丢失输出
xargs: losing output when redirecting stdout to a file in parallel mode
我在并行模式下使用 GNU xargs(版本 4.2.2),我似乎在重定向到文件时可靠地丢失了输出。重定向到管道时,它似乎工作正常。
以下 shell 命令演示了 minimum, complete, and verifiable example 的问题。我使用 xargs
生成 2550 个数字,将其分成每行 100 个参数,每行总共 26 行,其中第 26 行仅包含 50 个参数。
# generate numbers 1 to 2550 where each number is on its own line
$ seq 1 2550 > /tmp/nums
$ wc -l /tmp/nums
2550 /tmp/nums
# piping to wc is accurate: 26 lines, 2550 args
$ xargs -P20 -n 100 </tmp/nums | wc
26 2550 11643
# redirecting to a file is clearly inaccurate: 22 lines, 2150 args
$ xargs -P20 -n 100 </tmp/nums >/tmp/out; wc /tmp/out
22 2150 10043 /tmp/out
我认为问题与底层 shell 无关,因为 shell 将在命令执行并等待 xargs 完成之前执行重定向。在这种情况下,我假设 xargs 在刷新缓冲区之前完成。但是如果我的假设是正确的,我不知道为什么这个问题在写入管道时没有出现。
编辑:
在shell中使用>>
(create/append归档)时出现,问题似乎没有表现出来:
# appending to file
$ >/tmp/out
$ xargs -P20 -n 100 </tmp/nums >>/tmp/out; wc /tmp/out
26 2550 11643
# creating and appending to file
$ rm /tmp/out
$ xargs -P20 -n 100 </tmp/nums >>/tmp/out; wc /tmp/out
26 2550 11643
我知道这个问题是关于 xargs
的,但是如果您仍然遇到问题,那么 GNU Parallel 可能会有帮助。您的 xargs
调用将转换为:
$ < /tmp/nums parallel -j20 -N100 echo > /tmp/out; wc /tmp/out
26 2550 11643 /tmp/out
您的问题是由于混合了不同进程的输出。此处显示:
parallel perl -e '$a=\"1{}\"x10000000\;print\ $a,\"\n\"' '>' {} ::: a b c d e f
ls -l a b c d e f
parallel -kP4 -n1 grep 1 > out.par ::: a b c d e f
echo a b c d e f | xargs -P4 -n1 grep 1 > out.xargs-unbuf
echo a b c d e f | xargs -P4 -n1 grep --line-buffered 1 > out.xargs-linebuf
echo a b c d e f | xargs -n1 grep 1 > out.xargs-serial
ls -l out*
md5sum out*
解决方案是缓冲每个作业的输出 - 在内存或 tmp 文件中(就像 GNU Parallel 所做的那样)。
我在并行模式下使用 GNU xargs(版本 4.2.2),我似乎在重定向到文件时可靠地丢失了输出。重定向到管道时,它似乎工作正常。
以下 shell 命令演示了 minimum, complete, and verifiable example 的问题。我使用 xargs
生成 2550 个数字,将其分成每行 100 个参数,每行总共 26 行,其中第 26 行仅包含 50 个参数。
# generate numbers 1 to 2550 where each number is on its own line
$ seq 1 2550 > /tmp/nums
$ wc -l /tmp/nums
2550 /tmp/nums
# piping to wc is accurate: 26 lines, 2550 args
$ xargs -P20 -n 100 </tmp/nums | wc
26 2550 11643
# redirecting to a file is clearly inaccurate: 22 lines, 2150 args
$ xargs -P20 -n 100 </tmp/nums >/tmp/out; wc /tmp/out
22 2150 10043 /tmp/out
我认为问题与底层 shell 无关,因为 shell 将在命令执行并等待 xargs 完成之前执行重定向。在这种情况下,我假设 xargs 在刷新缓冲区之前完成。但是如果我的假设是正确的,我不知道为什么这个问题在写入管道时没有出现。
编辑:
在shell中使用>>
(create/append归档)时出现,问题似乎没有表现出来:
# appending to file
$ >/tmp/out
$ xargs -P20 -n 100 </tmp/nums >>/tmp/out; wc /tmp/out
26 2550 11643
# creating and appending to file
$ rm /tmp/out
$ xargs -P20 -n 100 </tmp/nums >>/tmp/out; wc /tmp/out
26 2550 11643
我知道这个问题是关于 xargs
的,但是如果您仍然遇到问题,那么 GNU Parallel 可能会有帮助。您的 xargs
调用将转换为:
$ < /tmp/nums parallel -j20 -N100 echo > /tmp/out; wc /tmp/out
26 2550 11643 /tmp/out
您的问题是由于混合了不同进程的输出。此处显示:
parallel perl -e '$a=\"1{}\"x10000000\;print\ $a,\"\n\"' '>' {} ::: a b c d e f
ls -l a b c d e f
parallel -kP4 -n1 grep 1 > out.par ::: a b c d e f
echo a b c d e f | xargs -P4 -n1 grep 1 > out.xargs-unbuf
echo a b c d e f | xargs -P4 -n1 grep --line-buffered 1 > out.xargs-linebuf
echo a b c d e f | xargs -n1 grep 1 > out.xargs-serial
ls -l out*
md5sum out*
解决方案是缓冲每个作业的输出 - 在内存或 tmp 文件中(就像 GNU Parallel 所做的那样)。