変数が拡張されるようにSSHを介してリモートでforループを実行する方法は?

変数が拡張されるようにSSHを介してリモートでforループを実行する方法は?

lsリモートホストのforループにファイルがない場合はすべて正常ですが、変数をキャプチャして各ファイルを試してみると、変数がls拡張echoされていないか値がないため失敗します。

私が言いたいことは:

IFS=$'\n'
servers=(
  blue
  green
  red
)
for i in ${servers[@]}; do 
   ssh $i "
     ls /dir/xyz_${i}*/details.txt
   "
done
/dir/xyx_blue0/details.txt 
/dir/xyz_blue1/details.txt
/dir/xyx_green2/details.txt 
/dir/xyz_green4/details.txt
/dir/xyx_red1/details.txt 
/dir/xyz_red8/details.txt

lsただし、実際にはファイルを操作できるように出力を繰り返す必要がありますが、変数は拡張されません。

for i in ${servers[@]}; do 
   ssh $i "
     for i in $(ls /dir/xyz_${i}*/details.txt); do 
        echo $i
     done
   "
done
not found: /dir/xyx_blue*/details.txt 
not found: /dir/xyx_green*/details.txt 
not found: /dir/xyx_red*/details.txt 

$iリモートホストでループを実行するときにどのように拡張しますか?

ベストアンサー1

問題は、リモートサーバーで実行したいコマンドの置き換えがローカルで実行されることです。これは、置換が二重引用符内にあるためです。これは、ローカルシェルが呼び出す前に拡張を計算することを意味しますssh

また、出力を読むlsことは賢明ではありません(参照:なぜ`ls`を解析しないのですか*(そしてどうすればいいですか?))。

代わりに:

servers=(
  blue
  green
  red
)

for server in "${servers[@]}"; do
    ssh -T "$server" <<END_SCRIPT
shopt -s nullglob
for pathname in /dir/xyz_$server*/details.txt; do
    printf 'file path is "%s"\n' "\$pathname"
done
END_SCRIPT
done

これはリモートサーバーに送信されるスクリプトで、引用符なしで「here-document」を使用します。スクリプトは、最初にパターンがファイル名と一致しない場合、内部ループ内のループを防ぐためにnullglobシェルオプション(リモートシェルがあると仮定)を設定します。bashその後、現在のサーバー名に置き換えられるパターンを繰り返します/dir/xyz_$server*/details.txt$server

その後、ループはどのファイル名がパターンと一致するかについての短いメッセージを出力し、コードは変数が$pathname一致しないことを確認します。地元のエスケープしてシェル$

$inはエスケープさ$serverれないので、私たちが望むローカルシェルによって拡張されますが、$inは$pathname次のようにエスケープする必要があります。止めるローカル拡張。

IFSデフォルト以外の値を設定する必要はありません。私はあなたが配列割り当てを書くことができるように、または他の理由でこれを行うと仮定しますが、上記のコードのどれもこれを要求しません。

私は疑似TTY割り当てを明示的にオフにするために-Twithを使用します。ssh


あなたできる必要と思われる場合は、スクリプトを単一の文字列として提供することもできます。

servers=(
  blue
  green
  red
)

for server in "${servers[@]}"; do
    ssh "$server" "
shopt -s nullglob
for pathname in /dir/xyz_$server*/details.txt; do
    printf 'file path is \"%s\"\n' \"\$pathname\"
done"
done

この場合、含まれる各二重引用符がエスケープされていることを確認する必要があります(そうしないと、リモートシェルスクリプトを構成する二重引用符で囲まれた文字列は終了します)。

おすすめ記事