입력 파일을 읽고 heredoc을 사용하여 서버에 ssh로 연결하는 bash 스크립트가 있지만 입력 파일에서 일부 특수 문자를 이스케이프 처리하는 데 문제가 있습니다. 이것이 내가 가진 것입니다 ...
다음을 포함하는 input.txt라는 파일이 있습니다.
1.2.3.4:abcdefg
2.3.4.5:abc$def
아래와 같이 bash 스크립트가 있습니다. 비밀번호에 "$" 문자가 포함되어 있지 않으면 잘 작동하지만, 비밀번호에 "$"가 포함되어 있으면 $ 뒤의 부분을 변수로 처리하기 때문에 작동이 중단됩니다.
#!/bin/bash
if [ -e "input.txt" ]; then
while read i; do
/usr/bin/expect <(cat << EOD
set timeout 15
spawn ssh "user@$(echo $i | cut -d: -f 1)"
#######################
expect "yes/no" {
send "yes\r"
expect "Password:" { send "$(echo $i | cut -d: -f 2)\r" }
} "Password:" { send "$(echo $i | cut -d: -f 2)\r" }
expect -re "day: $" { send "\r" }
expect ":" { send "\r" }
expect -re "# $" { send "date\r" }
expect -re "# $" { send "exit\r" }
EOD
)
done < input.txt
fi
이것을 실행하고 두 번째 IP 세트에 도달하면 다음 오류가 발생합니다.
spawn ssh [email protected]
Unauthorized use of this system is prohibited and may be prosecuted
to the fullest extent of the law. By using this system, you implicitly
agree to monitoring by system management and law enforcement authorities.
If you do not agree with these terms, DISCONNECT NOW.
Password: can't read "def": no such variable
while executing
"send "abc$def\r" "
invoked from within
"expect "yes/no" {
send "yes\r"
expect "Password:" { send "abc$def\r" }
} "Password:" { send "abc$def\r" }"
(file "/dev/fd/63" line 5)
누구든지 어떤 아이디어가 있습니까? 나는 큰 따옴표 안에 작은 따옴표와 내가 생각할 수 있는 모든 것을 시도했지만 여전히 작동하지 못했습니다. 미리 감사드립니다
답변1
여기 문서의 변수를 확장하지 않으려면 EOD를 인용하세요.
cat << 'EOD'
...
EOD
예를 들어 다음 파일은 다음과 같습니다.
cat <<EOF
test\$literal
var$(echo this)
EOF
다음 결과가 생성됩니다.
test$literal
varthis
답변2
문제는 여기의 셸이나 문서에 있는 것이 아니라 변수를 $def
변수로 참조하고 확장하려는 Expect에 있습니다.
여기서 bar
변수는 Expect에 설정되어 확장됩니다(이것은 작은따옴표이므로 쉘은 이를 확장하지 않습니다 $bar
).
$ expect -f - <<< 'set bar abcdefg; send_user "foo$bar\n"'
fooabcdefg
이는 여러분이 본 것과 동일한 오류를 발생시킵니다(예상 스크립트는 이제 큰따옴표로 묶여 있으므로$var
하다이전과 다르게 셸에서 확장합니다.):
$ var='foo$bar'; expect -f - <<< "send_user \"$var\n\""
can't read "bar": no such variable
while executing
"send_user 'foo$bar\n'"
탈출해야 $
하지만 적어도 탈출해야 합니다. [
왜냐하면 이는 Expect나 오히려 Expect의 기반이 되는 Tcl에서도 특별하기 때문입니다. 아마 다른 분들도 계실 것 같은데 잘 모르겠네요...
명령줄 인수를 통해 값을 전달하는 것이 더 쉬울 수 있습니다.
$ var='foo$bar[quux]'
$ expect -f - "$var" <<< 'set var [lindex $argv 0]; send_user "$var\n"'
foo$bar[quux]
또는 환경을 통해:
$ export var
$ expect -f - "$var" <<< 'set var $::env(var); send_user "$var\n"'
foo$bar[quux]
코드의 기능에 더 가깝습니다.
#!/bin/bash
line='2.3.4.5:abc$def'
IFS=: read host pw <<< "$line"
export host pw
expect -f - << 'EOF'
set host $::env(host)
set pw $::env(pw)
send_user "host is '$host' pw is '$pw'\n"
EOF
환경을 통해 전달된 변수를 사용하면 쉘이 s를 확장하지 않고 필요한 경우 $
Expect 변수를 사용할 수 있도록 here-doc를 인용할 수 있습니다 $host
.$pw
답변3
문제는 쉘 코드와 예상 코드를 혼합하는 데서 발생합니다. 이 작업은 매우 간단합니다. Expect에 코드를 작성하면 됩니다.
#!/usr/bin/expect -f
set timeout 15
set fh [open "input.txt" r]
while {[gets $fh line] != -1} {
# using a regular expression allows a colon in the password.
regexp {^([^:]+):(.*)} $line -> host passwd
spawn ssh user@$host
expect {
"yes/no" { send "yes\r"; exp_continue }
"Password:" { send "$passwd\r" }
}
expect -re "day: $" { send "\r" }
expect ":" { send "\r" }
expect -re "# $" { send "date\r" }
expect -re "# $" { send "exit\r" }
expect eof
}
close $fh