いつものように基本的知識の不足ゆえ、久々にドハマりしてしまったのでメモ。
(前提)
- やりたいこと:PHPプログラム(Web画面)からexec関数を実行し、SCPを使って外部サーバへファイルをリネームしながら転送
- SCPの実行に当たっては、本来は公開鍵方式でやるべきだが、相手先サーバの事情によりパスワード認証方式で実行せねばならない。
⇒シェルのexpectコマンドを使ってSCPを実行し、疑似対話イメージでパスワードを指定することにした。
expect -c "
set timeout 30
spawn /usr/bin/scp (転送元ディレクトリ)/hoge.txt root@(転送先サーバ):(転送先ディレクトリ)/hogefuga.txt
expect default { exit 10 } \"root@(転送先サーバ)'s password: \" ; send \"(転送先サーバパスワード)\n\"
interact
"
(発生した事象)
- PHPプログラムを実行したところ、転送先サーバにリネーム後のファイルがコピーされない。
- ただし、転送先にリネーム後と同名のファイルがあれば、正しく上書きされる。
- 上記SCPコマンドをコマンドラインから実行すると、転送先の同名ファイルの有無にかかわらずリネーム後のファイルが正しくコピーされる。
当初はPHPの設定の問題かと、その近辺をあれこれ調べましたが、該当する要素は見つからず・・・
(原因)
- expectコマンド中のパスワード送信時の改行コードが誤っていました("\r"が正)。
- 何より、expectで指定しているコマンド中の"interact"が悪さしてた模様です。
manによれば、"interact"はプロセスの制御をユーザーに渡すコマンドのため、上記の例では標準入出力がシェルに戻ってしまうそうで。
それでリネームファイルがコピーできない原理は「?」なのですが、ともあれ望ましい姿にはすべきでしょう。
⇒対話形式シェルのソースをサンプルにして、よー調べんとコピーしたのがあかんかったようです・・・
(対応)
expectコマンドの内容を、(参考)のページを参考に修正し、結果正しくコピーできるようになりました。
expect -c "
set timeout 30
spawn /usr/bin/scp (転送元ディレクトリ)/hoge.txt root@(転送先サーバ):(転送先ディレクトリ)/hogefuga.txt
expect default { exit 10 } \"root@(転送先サーバ)'s password: \" ; send \"(転送先サーバパスワード)\n\"
expect {\"100%\" { exit 0}}
"
(参考)
シェル以外からexpectしててハマったメモ
※鬼のようにググっていたら、たまたまヒットしたのがラッキーでした