在后台运行多个 bash 函数并等待它们返回

syn*_*gma 20 bash background-process

这是一个简单的脚本,它nvidia-smi在多个主机上运行命令并将其输出保存到一个公共文件中。这里的目标是让它异步运行。

&在结束process_host()函数调用是否足够?我的脚本正确吗?

#!/bin/bash

HOSTS=(host1 host2 host3)
OUTPUT_FILE=nvidia_smi.txt

rm $OUTPUT_FILE

process_host() {
    host=$1
    echo "Processing" $host
    output=`ssh ${host} nvidia-smi`
    echo ${host} >> $OUTPUT_FILE
    echo "$output" >> $OUTPUT_FILE
}

for host in ${HOSTS[@]}; do
    process_host ${host} &
done;

wait
cat $OUTPUT_FILE
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 18

是的,您的脚本是正确的,但您的输出可能会出现乱码或乱序。最好让函数根据主机名将其输出写入特定文件,然后让主脚本连接结果(并清理)。

此外,你应该双引号你的变量。将脚本复制并粘贴到ShellCheck 中

也许是这样的:

#!/bin/bash

hosts=( host1 host2 host3 )
outfile="nvidia_smi.txt"

rm -f "$outfile"

function process_host {
    local host="$1"
    local hostout="$host.out"
    printf "Processing host '%s'\n" "$host"
    echo "$host" >"$hostout"
    ssh "$host" nvidia-smi >>"$hostout"
}

for host in "${hosts[@]}"; do
    process_host "$host" &
done

wait

for host in "${hosts[@]}"; do
    hostout="$host.out"
    cat "$hostout"
    rm -f "$hostout"
done >"$outfile"

cat "$outfile"
Run Code Online (Sandbox Code Playgroud)

最后一个循环可以替换为

cat "${hosts[@]/%/.out}" >"$outfile"
rm -f "${hosts[@]/%/.out}"
Run Code Online (Sandbox Code Playgroud)

2021 年再看看我 2016 年的旧答案,我今天可能会写这样的代码:

#!/bin/bash

hosts=( host1 host2 host3 )
outfile="nvidia_smi.txt"

rm -f "$outfile"

function process_host {
    local host="$1"
    local hostout="$host.out"
    printf "Processing host '%s'\n" "$host"
    echo "$host" >"$hostout"
    ssh "$host" nvidia-smi >>"$hostout"
}

for host in "${hosts[@]}"; do
    process_host "$host" &
done

wait

for host in "${hosts[@]}"; do
    hostout="$host.out"
    cat "$hostout"
    rm -f "$hostout"
done >"$outfile"

cat "$outfile"
Run Code Online (Sandbox Code Playgroud)

这是更短的,因为我们真的不需要任何命名数组,我们可以用/bin/sh代替bash. 要连接的主机列表保存在位置参数列表中。我还删除了循环内的信息输出以及 shell 函数(实际上并没有做太多)。

使用适当的临时文件而不是组成可能已经被采用的文件名的变体:

cat "${hosts[@]/%/.out}" >"$outfile"
rm -f "${hosts[@]/%/.out}"
Run Code Online (Sandbox Code Playgroud)

这会将位置参数中的主机名替换为包含该主机输出的临时文件的路径名。

  • @ΔλЛ 例如,如果第一个主机响应缓慢,则“正在处理主机1”之后将是“正在处理主机2”和来自“主机2”的输出,而不是来自“主机1”的输出。 (2认同)