SSH를 통해 비밀번호로 보호된 여러 컴퓨터를 재부팅하는 bash 스크립트를 작성하려고 합니다. .txt 파일에 모든 IP 목록이 있고 스크립트가 거기에서 IP를 읽도록 하려고 합니다. 내 Mac에는 sshpass가 없기 때문에 Expect 명령을 사용하여 장난을 쳤습니다. sshpass 없이 할 수 있는 방법이 있나요?
지금까지 나는 이것을 가지고 있습니다 :
#!/bin/bash
for server in 'testreboot.txt'; do
expect -c 'spawn ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5
administrator@$server "sudo shutdown -r now"; expect "Password:"; send
"password\r"; interact'
done
testreboot.txt에는 테스트 머신의 IP 주소만 나열합니다. 가능합니까, 아니면 변수에 할당해야 합니까? 실행하려고 하면 계속해서 다양한 오류가 발생합니다.
답변1
문자열을 작은따옴표로 묶어서 셸이 삽입하는 것을 방지합니다 $server
. TCL( 코드 작성 방식)도 이 형식을 사용하여 변수를 삽입하지만 expect
TCL 코드에서는 $server
이 형식을 사용하지 않습니다 . set server ...
따라서 쉘이 이를 삽입하지 않고 TCL이 이를 설정하지 않기 때문에 오류가 발생합니다. 한 가지 방법은 TCL 표현식을 큰따옴표로 묶어서 쉘이 $server
쉘 변수에 삽입할 수 있도록 하는 것입니다.
$ server=example; expect -c 'puts $server'
can't read "server": no such variable
while executing
"puts $server"
$ server=example; expect -c "puts $server"
example
$
그러나 이는 "
쉘 보간을 방해하지 않도록 TCL 코드의 모든 항목을 이스케이프해야 함을 의미합니다. 이는 특히 명령이 더 길고 복잡해짐에 따라 빠르게 추악해지고 디버그하기 어려워질 수 있습니다.
$ server=example; expect -c "puts \"a server named '$server'\""
a server named 'example'
$
또 다른 옵션은 매개변수를 TCL 변수로 읽는 것입니다. 그러나 아쉽게도 -c
플래그 코드는expect
매개변수 목록에 접근할 수 없습니다.매개변수 목록이 TCL에 사용 가능해지기 전에 char *argv[]
코드가 실행되기 때문입니다 . -c
따라서 이를 TCL 변수로 사용하려면 $server
스크립트를 TCL로 다시 작성해야 합니다.
#!/usr/bin/env expect
set fh [open testreboot.txt r]
while {[gets $fh server] >= 0} {
spawn -noecho ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
administrator@$server
expect -ex "Password:"
send "Hunter2\r"
expect -ex {$ }
send "sudo shutdown -r now\r"
expect -ex "Password:"
send "Hunter2\r"
interact
}
이를 위해서는 향상된 오류 처리, 시간 초과, 더 나은 쉘 프롬프트 일치 등이 필요할 수 있습니다.