smartctl
複数のリモートホストにログインし、(パッケージ内の)配列で定義されたディスクで実行されるBashスクリプトを作成しました。配列はリモートホストに渡すことができますが、スクリプトは最初の要素を繰り返し繰り返し表示します。配列を文字列として扱い、最初の要素以降のすべての要素を無視するようです。smartmontools
DISKS
DISKS=("/dev/sda" "/dev/sdb" "/dev/sdc")
HOSTS=("Ariadne" "Nyx")
for i in "${HOSTS[@]}"; do
ssh "$i" "bash" << EOF
for j in "${DISKS[@]}"; do
echo "$j"
done
EOF
done
リモートホストで(2番目のforループの前に)配列を定義しようとしましたが、DISKS=("${DISKS[@]}")
役に立ちませんでした。
SSHを介してアレイをリモートホストに正しく渡し、アレイを繰り返すにはどうすればよいですか?
答え1
次のように配列の定義をリモートで渡すことができますbash
(これはリモートユーザーのログインシェルがあると仮定しますbash
)。
DISKS_definition=$(typeset -p DISKS)
for i in "${HOSTS[@]}"; do
ssh "$i" "$DISKS_definition"'
for j in "${DISKS[@]}"; do
echo "$j"
done'
done
またはここで説明されている方法を使用する場合:
DISKS_definition=$(typeset -p DISKS)
for i in "${HOSTS[@]}"; do
ssh "$i" bash <<EOF
$DISKS_definition
for j in "\${DISKS[@]}"; do
echo "\$j"
done
EOF
done
ssh
クライアントとサーバーが変数の受け渡しを許可している場合は、LC_*
この操作も実行できます。
DISKS_definition=$(typeset -p DISKS)
for i in "${HOSTS[@]}"; do
LC_DISKS=$DISKS_definition ssh "$i" bash <<'EOF'
eval "$LC_DISKS"
for j in "${DISKS[@]}"; do
echo "$j"
done
EOF
done
参照のすべての内容は、拡張を実行するローカルまたはリモートシェルを決定します。変数は二重引用符内で拡張され、ここでは区切り文字が引用符で囲まれていない文書<<'EOF'
で拡張される<<EOF
ことに注意してください。ローカルシェルによって拡張されます)。
非ASCIIデータを含む配列の場合、ローカルおよびリモートシステムのロケールの文字セットが同じであることを確認するか、少なくともUTF-8以外のマルチバイト文字セットを使用しないでください。
bash-4.3$ locale charmap
ISO-8859-1
bash-4.3$ a=($'foo\xa3$(uname>&2)bar' baz)
bash-4.3$ a_definition=$(typeset -p a)
bash-4.3$ LC_ALL=zh_HK.big5hkscs bash -c "$a_definition"
Linux
別の文字セットに切り替えると、内容の$a_definition
意味が異なります(ここでuname>&2
コマンドが実行されます)。
答え2
コマンドラインがecho "$j"
評価されると評価されるため、forループ内では実際には変数ではなく定数(および未定義)です。ssh
for j...
この試み
for i in "${HOSTS[@]}"; do
ssh "$i" "bash" << EOF
for j in "${DISKS[@]}"; do
echo "\$j"
done
EOF
done
または、$DISKS
配列に空白なしで安全な単語が含まれている場合。
for i in "${HOSTS[@]}"; do
ssh "$i" "for j in ${DISKS[@]}; do echo \"\$j\"; done"
done
このような問題を解決するために私が好む方法は、必要なタスクを実行するスクリプトを作成して各リモートサーバーに常駐させることです。その後、各サーバーでスクリプトを呼び出すプロセスは簡単で簡単です。
for h in "${HOSTS[@]}"; do ssh "$h" /usr/local/bin/myscript; done
スクリプトが古くなるかどうか心配している場合は、実行する前にローカルシステムからファイルをコピーすることは不可能な作業ではありません。次のように動作します。
for h in "${HOSTS[@]}"
do
scp -p /local/path/to/myscript "$h":myscript.$$
ssh "$h" "myscript.$$; rm -f myscript.$$"
done