这是一个简单的脚本,它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}"
到 2021 年再看一下我 2016 年的旧答案,我今天可能会写这样的代码:
#!/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
。相反,要连接的主机列表保存在位置参数列表中。我还删除了循环内的信息输出以及 shell 函数(实际上并没有做太多事情)。
一种使用适当的临时文件而不是组成可能已被采用的文件名的变体:
#!/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.'
这会将位置参数中的主机名替换为包含该主机输出的临时文件的路径名。