カスタムポートを持つサーバーループの場合( "user1@server1 -p 12345" "user2@server2 -p 54321" ...; do)

カスタムポートを持つサーバーループの場合( "user1@server1 -p 12345" "user2@server2 -p 54321" ...; do)

SSHを介して一連のサーバーでコマンドを実行しようとしています。最近、インターネットスキャナを避けるためにSSHポートを変更しましたが、これはスクリプトを壊しました。 forループの各user@serverエントリに対して異なるポートを指定する「簡単な方法」を知っている人はいますか?

for i in '[email protected] -p 12345' '[email protected] -p 54321'
 do printf "\e[%sm%s\e[00m\n" 32 $i
 ssh $i crontab -l
done

2行目は、読みやすくするために出力する前にサーバー名を印刷します。

それが私に与えるのは幸せではありませんが、ssh: Could not resolve hostname server1.domain1.com -p 12345: Name or service not known

以前は、すべてのポートがデフォルト値22のときに機能し、指定する必要はありませんでした。

答え1

バージョン7.7以降、OpenSSH ssh(およびそのscp同僚sftp)はURI形式のターゲットを受け入れます。必要に応じて、ポート番号をURIの一部として指定できます。たとえば、「ssh://someuser@somehost:42」はポート 42 に接続されます。シェルに関する限り、URIの利点は、焦点を合わせる単一の文字列であることです。だからあなたはこれを行うことができます:

for i in 'ssh://[email protected]:12345' 'ssh://[email protected]:54321'
 do printf ...
 ssh "$i" ...
done

SSH URIの一般的な形式は「ssh://user@host:port」です。 「user」と「port」の両方の部分はオプションであり、値を指定する必要がない場合は、「@」または「:」の句読点で省略できます。

答え2

正しい方法は、すべての接続ですべてを指定するのではなく、構成に保存することです。

あなたが持つことができる場所~/.ssh/config

Host server1.domain1.com  # When connecting to this
User user1  # Use this user
Port 12345  # with this port

Host serv2  # We can also use a different, internal, name
Hostname server1.domain1.com  # The actual hostname or IP it will use to connect
User user2
Port 54321

これにより、正しいことがssh server1.domain1.com行われます™各コンピュータで使用されているユーザー名またはポートを覚えておく必要はありません。ssh serv2スクリプトと人間の両方に最適です。

後でポートを変更すると、1 か所で変更できます。

ワイルドカードも使用できるため、すべてのシステムでsshdがポート1234をリッスンしている場合は、個別にリストすることなくすべてを一致domain1.comさせることができます。Host *.domain1.com

答え3

for複数の変数を繰り返すことができるループの場合、変数を引用せずにすでにzsh構文を使用しています。zsh

# zsh
for colour host port (
  green [email protected] 12345
  blue  [email protected] 54321
) {
  print -rP "%F{$colour}%B$host:$port%b%f"
  ssh -p $port $host 'crontab -l'
}

パラメータリストを繰り返すには、多次元配列を含むシェルを使用できますksh93。たとえば、次のようになります。

# ksh93
ssh_args=(
  (-p 12345 [email protected])
  (-p 54321 [email protected])
)
for i in "${!ssh_args[@]}"}; do
  printf '\e[1;32m%s\e[m\n' "${ssh_args[i][2]}"
  ssh "${ssh_args[i][@]}" 'crontab -l'
done

または、文字列に表示されないことがわかっている文字を使用して、パラメータに関連付けられた文字列を含む配列要素を作成して分離します。zsh確かに分裂的な性格です${(s[x])var}

kshとbashも動作しますが、拡張機能を参照することを忘れたときに暗黙的に呼び出される薄暗い分割+globを介してのみ機能します。次のように使用できます。

# ksh93 / bash / yash / mksh / zsh --emulate ksh
ssh_args=(
  -p:12345:[email protected]
  -p:54321:[email protected]
)
IFS=:; set -o noglob # tune your split+glob operator by specifying
                     # the separator and disabling globbing
for joined_args in "${ssh_args[@]}"; do
  args=( $joined_args ) # invoke split+glob
  printf '\e[1;32m%s\e[m\n' "${args[2]}"
  ssh "${args[@]}" 'crontab -l'
done

要素を区切るのではなく空白を使用しますが、グローバルを:設定または無効にしないことを除いて、デフォルトではメソッドによって実行されます。$IFS

$i分割しないという事実は、$IFS空の文字列に設定するか、コードがbashの代わりにzshによって実行されるという事実として説明できます。ここで、分割やワイルドカードの指定は、引数拡張時に暗黙的には行われません。

zshでIFSを分割したい場合は、ワイルドカードが必要な場合は$=var代わりに使用してください。 bashはzshに似ています。したがって、zshには次のものが必要です。$var$~var$var$=~var

# zsh
ssh_args=(
  -p:12345:[email protected]
  -p:54321:[email protected]
)
IFS=:
for joined_args in $ssh_args; do
  args=( $=joined_args ) # split on $IFS or better:
  args=( ${(s[:])joined_args} ) # split explicitly on : without
                               # having to touch $IFS
  print -rP "%F{green}%B$host[-1]%b%f"
  ssh $args 'crontab -l'
done

可能な移植可能なアプローチshは、次のように書くことです。

# sh / bash / dash / ksh / yash / zsh...
while IFS=' ' read<&3 host port; do
  {
    printf '\33[1;32m%s\e[m\n' "$host:$port"
    ssh -p "$port" "$host" 'crontab -l'
  } 3<&-
done 3<< 'EOF'
[email protected] 12345
[email protected] 54321
EOF

次のように値の前にバックスラッシュを追加して、値に区切り文字(ここではスペース)を含めることができる-rオプションを省略します。read

john\ doe@server1 1234

ただし、他の方法とは異なり、これらの値に改行文字を含めることはできません(ユーザー、ホスト、サービス名、またはポート番号に問題がない可能性があります)。

すべてのリストの要素数が同じで$n制限がない別の移植可能な循環リストは、すべての要素を位置引数に格納してループ内で繰り返すことですwhile [ "$#" -ge "$n" ]; do something with "$1" "$2"...; shift "$n"; done。だからここにあります:

# sh / bash / dash / ksh / yash / zsh...
eval "$(
  printf "fg_%s='\33[3%sm' " \
    black 0 red     1 green 2 yellow 3 \
    blue  4 magenta 5 cyan  6 white  7
  printf "bg_%s='\33[4%sm' " \
    black 0 red     1 green 2 yellow 3 \
    blue  4 magenta 5 cyan  6 white  7
  printf "attr_%s='\33[%sm' " \
    reset '' bold     1 dim     2 italics 3 underline 4 \
    blink 5  standout 7 reverse 7 secure  8
)"
    
set -- \
  "$fg_green$attr_bold" [email protected] 12345 \
  "$bg_blue$fg_white"   [email protected] 54321

while [ "$#" -ge 3 ]; do
  colour=$1 host=$2 port=$3
  printf '%s\n' "$colour$host:$port$attr_reset"
  ssh -p "$port" "$host" 'crontab -l'
  shift 3
done

答え4

複数のホストでpdshを使用します。クラスタホスト数が多いデータセンターで広く使用されています。

pdshドキュメントから..

ホストh0、h1、h2ではユーザ「foo」で実行し、ホストh3、h5ではユーザ「bar」として実行します。

pdsh -w foo@h[0-2],bar@h[3,5]

https://code.google.com/archive/p/pdsh/wikis/UsingPDSH.wiki

Ángelが述べたように、このツールはSSH設定ファイルで動作します。

以下の完全な例..

~/.ssh/config

Host server1
Hostname server1
User user1  
Port 12345  

Host server2
Hostname server2
User user2
Port 54321

今すぐ実行してください。

pdsh -w server1,server2 crontab -l 

関連情報