先日 「expect + scp でメタ文字(* : アスタリスク)を使用した際に失敗した時のメモ」 という記事を投稿しましたが、その続きの話です。
以下の様な expect を使用したスクリプトを用意しました。
接続先が Solaris で、SSH/SCP 接続時のプロンプトが「パスワード:」と日本語になっていましたので、
expect にもそのように設定しています。
$ cat test.sh#!/bin/bash
# expect の function
func_expect (){
expect -c "
spawn $1
expect {
\"Are you sure you want to continue connecting (yes/no)?\" {
send \"yes\r\"
expect \"パスワード:\"
send \"hogehoge\r\"
} \"パスワード:\" {
send \"hogehoge\r\"
}
}
interact
"
}
# ファイルを SCP で送信
func_expect "sh -c \"scp /var/tmp/test_from/*.txt root@192.168.1.1:/var/tmp/test_to\""
そして、このスクリプトを crontab に登録し、定期的に実行しようと考えていました。
が、、、ターミナル上では成功するのに cron だと失敗するという切ない結果に。。
結論から言うと、上記は以下 2 つの理由で失敗します。
- interact は cron ではアカン
- cron だと LANG の設定が消える(cron 実行ユーザの LANG 設定にはならない)
一つ目、interact ですが、man を読むとこう書いてありました。
interact [string1 body1] ... [stringn [bodyn]]は 、現プロセスの制御をユーザーに渡す。結果、現プロセスに送られたキーストロークと現プ
ロセスの標準出力と標準エラー出力が復帰する。
おおぅ、cron では使えなさそう... ネットでぱっと見つけた情報をコピペするのは危険ですね。
この情報はぐぐってもたくさん出て来ました。
参考例:えくすぺくと | novaの日記 | スラッシュドット・ジャパン
ということで、以下のように編集!
戻りの文字列を echo で出すようにして、その文字列を見て exit させるようにしました。
終る時間も scp が長引く事も考え、「set timeout」を追加。
最後の echo $? が 3 であれば、ちゃんと終了文字を拾ってくれるかどうか分かります(確認用)。
$ cat test.sh#!/bin/bash
# expect の function
func_expect (){
expect -c "
set timeout 60
spawn $1
expect {
\"Are you sure you want to continue connecting (yes/no)?\" {
send \"yes\r\"
expect \"パスワード:\"
send \"hogehoge\r\"
} \"パスワード:\" {
send \"hogehoge\r\"
}
}
expect {
\"== expect END ==\" { exit 3 }
}
"
}
# ファイルを SCP で送信
func_expect "sh -c \"scp /var/tmp/test_from/*.txt root@192.168.1.1:/var/tmp/test_to ; echo '== expect END Flag ==' \""
echo $?
が、これもダメ、どうやら「パスワード」のところで止まっている模様...
その後試行錯誤して、cron で実行した際に LANG の設定が消える(C になる?)事が分かりました。
てっきり実行ユーザの LANG 設定が適用されると思っていました。
実際にスクリプトの途中に「set | grep LANG」を追加して、ターミナル上で手動実行した時は
LANG=ja_JP.UTF-8
と出ますが、cron で実行した時は何も出力されませんでした。
うまく日本語の処理ができず、expcet も失敗したと思われます。
最終的にはこうなりました。
export LANG="ja_JP.UTF-8" を追加しています。
$ cat test.sh#!/bin/bash
# expect の function
func_expect (){
expect -c "
set timeout 60
spawn $1
expect {
\"Are you sure you want to continue connecting (yes/no)?\" {
send \"yes\r\"
expect \"パスワード:\"
send \"hogehoge\r\"
} \"パスワード:\" {
send \"hogehoge\r\"
}
}
expect {
\"== expect END ==\" { exit 3 }
}
"
}
export LANG="ja_JP.UTF-8"
set | grep LANG
# ファイルを SCP で送信
func_expect "sh -c \"scp /var/tmp/test_from/*.txt root@192.168.1.1:/var/tmp/test_to ; echo '== expect END Flag ==' \""
echo $?
以下 cron で実行した結果(出力結果をファイルにリダイレクトしたもの)。
LANG で UTF-8 の設定にもなってるし、最後のリターンコードが 3 になった事を確認。
これでようやくうまく言った。。。
$ ./test.shLANG=ja_JP.UTF-8
_=LANG
spawn sh -c scp /var/tmp/test_from/*.txt root@192.168.1.1:/var/tmp/test_to ; echo '== expect END Flag =='
root@192.168.1.1's password:
M1.txt 100% 0 0.0KB/s 00:00
M2.txt 100% 0 0.0KB/s 00:00
M3.txt 100% 0 0.0KB/s 00:00
== expect END Flag ==
3
※「set | grep LANG」 や最後の $? は確認用ですので、本番用では削除しました。
ちなみに、solaris のパスワードプロンプトが日本語なのは困ってる人他にもいるみたい