
入力ファイルを読み込み、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
これを実行して2番目の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