• ベストアンサー

対話型のコマンドで入力する値をスクリプトに盛り込んで自動化したい

今まで変更した各種設定を一気に行うシェルスクリプトを作成して、サーバーを再セットアップしてもすぐに今までどおり使えるようにしようとしています。 スクリプト中に対話型のコマンドを記述すると、そこで処理が中断して、入力待ち状態になってしまいます。 しかし、入力値は大抵いつも同じですので、これをスクリプト中に記述して、処理が中断する回数を極力減少させたいと考えています。 passwdコマンドをechoコマンドと組み合わせて次のようにやってみました。 # echo "xxx xxx" | passwd user しかし次のように失敗してしまいました。 Changing password for user user. New password: Retype new password: New password: New password: passwd: Conversation error エラーメッセージより再入力がうまくできていないようです。 さらに3回目の入力が求められていますが、これも謎です。 このような対話型のコマンドとその入力値を全部シェルスクリプトに記述するなどして、処理を自動化する方法をご存知の方は、ぜひ教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
noname#243622
noname#243622
回答No.5

>サーバーを再セットアップすると毎回異なるssh_host_keyを生成するため、このSSHサーバーのクライアントとなりうるホストのknown-hostsを更新する処理が必要になり、これを初期設定スクリプト中で行いたいと考えています。 ssh_host_keyが毎回変わってしまうということであれば、今あるssh_host_keyをスクリプト中においてて、変わったssh_host_keyと入れ替えてしまえばいいんじゃないんでしょうか。 そうすれば、相手側のホストにファイルを追加したりしなくてすみます。 個人的にはそこまでして自動化する必要があるかどうか疑問ですが。 実際そのスクリプト自体は手動でキックするのでしょうし。 結局のところ、セットアップした状態を、GhostとかTrueImageといったイメージングソフトでバックアップしておいて、そこからリカバリするほうが一番簡単な話のような気がします。

zyousuke
質問者

補足

mazingaさん、決定的なご回答をありがとうございます。 頭が固すぎて、そのような代替案が思い浮かびませんでした。 私のやろうとしていたことは、せっかくのクライアントサーバー型システムの利点を無視することでした。 普通クライアント機はサーバー機よりも数が多いため、サーバー機の資源を変更することでクライアント機の設定を省略できるのであれば、迷わずこちらの手法を採用すべきでした。 そういうわけで、早速この方針でスクリプトを作成してみました。 具体的には、再セットアップする前のサーバー機の /etc/ssh/ssh_host_keyと/etc/ssh/ssh_host_key を保存しておき、再セットアップ時に生成されるこの2ファイルを、保存しておいた2ファイルで上書きするというようにしました。 これで、クライアント機のssh_known_hostsには、サーバー機の/etc/ssh/ssh_host_key.pubの内容が、始めから追加されていることになります。 しかし、このクライアント機を使用してサーバー機に接続してみると、なぜか未知のサーバーである旨の警告が表示されてしまうのです。 さらに、そのままログインすると、サーバー機に現存する/etc/ssh/ssh_host_key.pubとは異なる行がクライアント機のssh_known_hostsに追加され、以後、未知サーバーの警告は表示されなくなります。 サーバー機を何度か再セットアップして、この新しく追加された行が何なのか調査してみました。 調査の結果、この新しく追加された行は、上書きする前の/etc/ssh/ssh_host_key.pubの内容と一致することが分かりました。 どうやら、サーバー再セットアップ時に生成される/etc/ssh/ssh_host_keyと/etc/ssh/ssh_host_key.pubを、セットアップ前のもので上書きしただけでは、以前のSSHサーバーを復元できないようです。 /etc/ssh/ssh_host_keyの情報がログインユーザーには見えないサーバーの奥深くに埋め込まれているのでしょうかね。 mazingaさん、上記について何か情報をお持ちでしたら、ぜひとも教えてください。 さて、私が作成している全てを自動化するスクリプトに疑問の声があがっているようですが、 確かに、自分でもこのスクリプトは今まで消費した労力と比較すると、実用性はきわめて低いと思います。 ですのでmazingaさんの問に答えるとすれば、それは私のこだわりというか意地ですね。 また、実はシェルスクリプトを覚えたのはつい最近でして、今まで手作業でやっていたことが、いろいろ自動化できて感動したというのも、この全自動スクリプトの作成を思い立った一因だと思います。 TrueImageはよく耳にするので、いずれは勉強して導入したいと思います。 そうしたら、今作成しているスクリプトは無意味になってしまいますが・・・。 また、ディスク障害対策として、二重化やDATの導入も行く行くはやりたいです。 さらに、火災等の対策として、遠隔地への退避も、やっている人はやっているようで、バックアップについて本気で取り組むとなると色々考える必要があり、気が遠くなりますね。

その他の回答 (5)

noname#243622
noname#243622
回答No.6

>しかし、このクライアント機を使用してサーバー機に接続してみると、なぜか未知のサーバーである旨の警告が表示されてしまうのです。 >さらに、そのままログインすると、サーバー機に現存する/etc/ssh/ssh_host_key.pubとは異なる行がクライアント機のssh_known_hostsに追加され、以後、未知サーバーの警告は表示されなくなります。 どのユーザからログインしたいのかわかりませんが、対象ユーザのホームディレクトリにあるknown_hostsファイルを保存したものと交換またはコピーしておいてください。 (例:/root/.ssh/known_hosts, /home/user01/.ssh/known_hosts) どちらかというと、sshに関する設定ファイルを知っておいたほうがよいのではないですか。

zyousuke
質問者

お礼

mazingaさん、ご返信ありがとうございます。 known_hostsファイルはSSHクライアントが持っているファイルですので、サーバー機を再セットアップしても変更される心配はないのです。 No.5のmazingaさんの助言にあるとおり、SSHクライアントの資源には何も手を加えず、どうにかSSHサーバーを今までどおり使えるようにする方法はないかと考えています。 mazingaさん、長期間お付き合いいただき面目ないのですが、他に何か助言がありましたらよろしくお願いします。 すみません皆様からの回答を期待するばかりで自分ではほとんどSSHについて調査していませんでしたので、もう少し本腰を入れて学習します。

noname#243622
noname#243622
回答No.4

>しかし、鍵を交換するためには、sshやscpを利用する必要があり、やはりスクリプトが中断してしまうのです。 鍵交換は最初の1回だけ実施します。 また、スクリプト中に鍵交換を実施するような話になっていますが、そうではなくて、鍵交換はコマンドラインであらかじめ行ってください。 >サーバーに鍵を置くという操作を、スクリプトの実行に先立って行わなければならないのであれば、その時ついでにサーバーのファイルを編集するということもできてしまい、 スクリプト中でsshを実行する必要がなくなってしまうのです。 意味がわかりません。ファイルを編集するべきサーバは、たくさんあって(たとえば1000台とか)、そのときに任意に決まるのですか?それとも編集する作業は1回だけしかしないのですか?

zyousuke
質問者

お礼

mazingaさん、ご返信ありがとうございます。 今、私はサーバーを再セットアップしてログインした直後に実行するスクリプトを作成しようとしています。 これは、今までサーバーを再セットアップするたびに手作業で行っていた各種サービスの設定等、面倒な作業を自動で行うことを目指しています。 この初期設定スクリプトで、別のサーバーにあるファイルへ行を追加するという作業も行いたいのです。 別のサーバーとは毎回異なるサーバーではなく、常に特定のサーバーです。 その追加するファイルとはまさに今話題にあがっているSSHのknown-hostsというファイルです。 サーバーを再セットアップすると毎回異なるssh_host_keyを生成するため、このSSHサーバーのクライアントとなりうるホストのknown-hostsを更新する処理が必要になり、これを初期設定スクリプト中で行いたいと考えています。 初期設定スクリプト中でsshを使用するのは、以上の1回のみです。 この初期設定スクリプトは名前通り、サーバーを再セットアップしたら一番最初に実行するコマンドでありたいため、これの前準備としてあらかじめいくつかコマンドを実行することはせずに、全てを1個のスクリプトで行いたいのです。 ですので鍵の交換を自動化できないのであれば、不本意ですがスクリプト中でパスワードを入力して、SSH接続した方がスマートかなと思っています。 う~む、なかなかうまく説明できないのですが、伝われ私の思いよ。 mazingaさん、引き続き何か妙案が思い浮かんだら、ぜひともご提供ください。

noname#243622
noname#243622
回答No.3

> SSHで別のサーバーにログインして、そのサーバーの任意ファイルに行を追加するという一連の処理を自動化することでした。 SSHには秘密鍵認証という方法があって、秘密鍵を交換しておくことで、パスワードを入力しなくても相手のサーバに対してログインすることが出来ます。 簡単に言うと、ログインを行う側(ホストA)で秘密鍵と公開鍵を作成(ssh-keygen)し、公開鍵をログインされる側(ホストB)に対して公開鍵(~/.ssh/id_dsa.pub)を送信します。 --- hostA----(ssh)---->hostB --- 相手側ホストに対して何かしたければ、これでいいのですが、単純にファイルをコピーしたければ scp も使えます。

参考URL:
http://www.geocities.jp/turtle_wide/tools/sshpass.html
zyousuke
質問者

お礼

mazingaさん、いろいろ案を考えていただいてありがとうございます。 しかし、鍵を交換するためには、sshやscpを利用する必要があり、やはりスクリプトが中断してしまうのです。 サーバーに鍵を置くという操作を、スクリプトの実行に先立って行わなければならないのであれば、その時ついでにサーバーのファイルを編集するということもできてしまい、 スクリプト中でsshを実行する必要がなくなってしまうのです。 そしてスクリプト中でsshを実行しないということは、サーバーに鍵を置いておくという準備も不用になり、 最終的にはサーバーのファイルは手作業で編集しなさいという答えに行き着いてしまうのです~。 当初はスクリプト中で対話型のコマンドを自動的に実行するための記述法があると思いこんで質問に参ったのですが、 このようなコマンドは例えスクリプト中に埋め込んだとしても、ユーザーからの入力は必須であるという気がしてきました。 ですので、ひとまず全自動化はあきらめて、引き続きサーバー初期設定スクリプトを作成していきたいと思います。 ひとまずあきらめるというのは裏を返せば完全にはあきらめ切れていないということですので、 もし、何か画期的な方法がひらめいたら、ぜひとも教えてほしいのです。 mazingaさん、amru05さん、情報を暖めている皆さん、よろしくお願いします。

  • amru05
  • ベストアンサー率63% (33/52)
回答No.2

here documents で記述できますのでやってみてください。 例) passwd <<! xxxx xxxx ! <<! ~ ! までが、here documentsで、 キー入力パラメータを記述します。 !は、終了文字を表しますがパラメータに 使用しない文字を指定します。

参考URL:
http://www.tldp.org/LDP/abs/html/here-docs.html
zyousuke
質問者

お礼

amru05さん、ご返信ありがとうございます。 そういえばhere documentsは最近学習したのでした。 その手がありましたね! しかし、試してみたのですが、下のように、echoと組み合わせてやった場合と同じエラーになってしまいました。 # passwd user <<! > xxxx > xxxx > ! Changing password for user user. New password: Retype new password: New password: New password: passwd: Conversation error また、sshコマンドも試してみたのですが、ダメでした。 # ssh host.domain.jp <<! > yes > ! Pseudo-terminal will not be allocated because stdin is not a terminal. The authenticity of host 'host.domain.jp (192.168.xxx.xxx)' can't be established. RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx. Are you sure you want to continue connecting (yes/no)? here documentsでyesと入力しているのに(yes/no)?と表示されて、入力待ち状態になってしまいました。 う~む、amru05さんにはできて私にはできないということは環境がいけないのですかね。 amru05さん、何か思い当たることがありましたら教えてください。 もし環境の問題だとしたらhere documentsに頼らなくても、パイプやリダイレクションでも対応できる気がするのです。

noname#243622
noname#243622
回答No.1

パスワードの変更方法として一般的なのは ・expectコマンドを使用する という方法があります。使い方はいろいろありますし、expectパッケージにはたいていautopasswdというコマンドが付属してますからそちらを使ってみてください。 話の文脈からですと、大量にユーザを追加して初期パスワードを設定したいようですので、すでにユーザが存在していて、暗号化されたパスワード(/etc/shadowの第2フィールド)がわかっているのであれば、それをパスワードにして追加するのも手です。 useradd コマンドに "-p (暗号化されたパスワード)" というオプションがあります。

zyousuke
質問者

お礼

mazingaさん、ご返信ありがとうございます。 いろいろつっこまれることを懸念して真にやりたいことを隠蔽して、すみませんでした。 実は、対話型のコマンドが他に思いつかなかったのでpasswdを例に挙げただけだったのです。 私が今、真にやりたがっていることは、 SSHで別のサーバーにログインして、そのサーバーの任意ファイルに行を追加するという一連の処理を自動化することでした。 sshコマンドを実行するとログインパスワードが要求され、そこで処理が中断してしまうというわけです。 ですので、passwdに特化せず、汎用的に利用できる巧妙な技があれば教えてほしいと思っていたのです。 今思いついたのですが、例えばadsl-setupというコマンドは、そのコマンド中でいっぱい設定値を入力しますが、入力する値の順番が分かっていれば、どうにかして全ての値をスクリプト中に記述する等して、自動化できないかと考えているのです。 そういうわけでして、なんとか引き続きご回答よろしくお願いします! useraddの-pオプションを試してみました。 これを利用すればuseraddでパスワードを登録できるのでpasswdコマンドが省略できますね! expectパッケージは、レッドハットを最小構成でセットアップしているためか、私のサーバーには入っていませんでした。

関連するQ&A