バックグラウンドで複数のbash関数を実行し、返されるのを待ちます。

バックグラウンドで複数のbash関数を実行し、返されるのを待ちます。

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

答え1

はい、スクリプトは正しいですが、出力が壊れているか、順序が間違っている可能性があります。関数がホスト名に基づいて特定のファイルに出力を書き込んでから、基本スクリプトに結果をリンクしてクリーンアップさせることをお勧めします。

また、変数を二重引用符で囲む必要があります。スクリプトをコピーして貼り付けます。住宅検査

たぶん、次のようなものがあります。

#!/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"

最後のループは次のように置き換えることができます。

cat "${hosts[@]/%/.out}" >"$outfile"
rm -f "${hosts[@]/%/.out}"

2016年と2021年の以前の答えを見ると、今日は次のようなコードを書くことができます。

#!/bin/sh

set -- host1 host2 host3
outfile=nvidia_smi.txt

for host do
    ssh "$host" nvidia-smi >"$outfile-$host" &
done

echo 'Commands submitted, now waiting...'
wait

for host do
    cat "$outfile-$host"
    rm -f "$outfile-$host"
done >"$outfile"

echo 'Done.'

実際には名前付き配列は必要ないので、これは短いです。したがって、代わり/bin/shに実行できますbash。代わりに、接続するホストのリストが場所パラメータのリストに保存されます。また、ループ内の情報出力とシェル関数(実際に多くのことはしません)を削除しました。

使用可能なファイル名を構成するのではなく、適切な一時ファイルを使用するバリアント:

#!/bin/sh

set -- host1 host2 host3
outfile=nvidia_smi.txt

for host do
    tmpfile=$(mktemp)
    ssh "$host" nvidia-smi >"$tmpfile" &
    set -- "$@" "$tmpfile"
    shift
done

echo 'Commands submitted, now waiting...'
wait

# Concatenate the output files and delete them.
cat -- "$@" >"$outfile"
rm -f -- "$@"

echo 'Done.'

これは、場所パラメーターのホスト名をそのホストへの出力を含む一時ファイルのパス名に置き換えます。

関連情報