如何在bash脚本中自动打印来自多个后台进程的行?

如何在bash脚本中自动打印来自多个后台进程的行?,bash,unix,scripting,Bash,Unix,Scripting,在我编写的bash函数中,我通过ssh启动多个远程命令,并让它们在单独的后台进程中运行。每一个过程都会产生许多行文本,这些文本被合并在一起,然后进行排序。我的问题是,有时这些线混合在一起。即一行开始打印,在该行完成打印之前,另一行开始在同一行上打印 我的问题是,使打印输出原子化的最简单方法是什么,这样单个行就不会混合在一起(将整行穿插在一起就可以了——我只希望列对齐)?我的一个想法是保存每个并行后台进程的输出,然后按顺序合并它们,但我一直无法实现这一点(如果我知道如何正确地执行,这个方法对我来说

在我编写的bash函数中,我通过ssh启动多个远程命令,并让它们在单独的后台进程中运行。每一个过程都会产生许多行文本,这些文本被合并在一起,然后进行排序。我的问题是,有时这些线混合在一起。即一行开始打印,在该行完成打印之前,另一行开始在同一行上打印

我的问题是,使打印输出原子化的最简单方法是什么,这样单个行就不会混合在一起(将整行穿插在一起就可以了——我只希望列对齐)?我的一个想法是保存每个并行后台进程的输出,然后按顺序合并它们,但我一直无法实现这一点(如果我知道如何正确地执行,这个方法对我来说应该很好)。以下是我试图编写的脚本类型的概要,以供参考:

foo() {
    (
        pids=()
        for x in "$@"
        do
            (
                ssh $x 'some-high-latency-command-with-200-lines-of-data-output'
            ) &
            pids+=( $! )
        done
        for x in "${pids[@]}"
        do
            wait $x
        done
    ) 2> /dev/null
}

我会将每个
ssh
运行重定向到它自己的文件,然后合并它们。我也不会使用
wait
循环
wait
本身将等待所有后台进程,或者如果您真的只想使用
ssh
进程,可以说
wait${pids[*]}

我最终偶然发现了一个似乎可以在不创建文件的情况下工作的解决方案。显然,如果我使用
declare
将ssh的输出分配给一个变量,那么行将被保留,并且使用
echo
从该变量打印似乎是原子的。见下文:

foo() {
    (
        pids=()
        for x in "$@"
        do
            (
                declare output=$(ssh $x 'some-command-with-multiline-output')
                echo "$output"
            ) &
            pids+=( $! )
        done
        wait ${pids[*]}
    ) 2> /dev/null
}

在打印行之前,使用一些程序在本地重新组合行,例如:

ssh $x 'some-high-latency-command-with-200-lines-of-data-output' | perl -pe1

谢谢,for wait的语法稍微简化了一些事情,但本质上与for循环在更紧凑的表示法中做了相同的事情。不过,如果不创建文件也能做到这一点就好了。不过,shell本身并不能真正做到这一点。您可以尝试让background
ssh
成为backgrounded
ssh…|读l时;不回显“$l”>>文件;完成
,这将非常缓慢,因为免费循环的唯一目的是执行行缓冲,而不是无缓冲或块缓冲输出。这取决于你之后对数据的处理,将合并步骤推迟到以后将比复杂的
ssh
-到shell脚本管道更好、更可靠。实际上,我只是将输出管道化到
less
中,并选择带有
&
的行子集来比较机器上的各种统计数据。我甚至不需要永久保存数据。这些都是相对较短的实验,在多达8-10台并行机器上只需10秒钟。但是,我经常运行这些测试,因此脚本的好处是,不用手动比较各个输出。