사용자 정의 포트가 있는 서버 루프의 경우("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

두 번째 줄은 가독성을 위해 출력하기 전에 서버 이름을 인쇄합니다.

그것이 나에게 주는 것은 행복이 아니지만,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스크립트와 인간 모두에게 좋습니다.

나중에 포트를 변경하면 한 곳에서 수정할 수 있습니다.

와일드카드도 사용할 수 있으므로 모든 시스템에 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 

관련 정보