MB blog

こちらは主に自分用のメモです。

パスワードなしの公開鍵認証でssh接続

expectで対話型シェルでは、bashの中でexpectスクリプトを読み込ませていますが、このサンプルには以下のような弱点があります。

これらをクリアするために、ssh-agentで公開鍵を生成して、パスワードなしでsshが使えるようにしておきます。

1. 鍵の生成

以下のコマンドで鍵を生成します。

ssh-keygen -t rsa

-tは、暗号方式を指定しています。

Enter file in which to save the key (/home/username/.ssh/id_rsa):

デフォルトでは、ホームディレクトリの.ssh以下に生成されます。何も入力せずエンターを押せばデフォルトを受け入れます。
次に、パスフレーズを訊かれるので、

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

何も入力せずエンターを押すと、パスワードなしで接続可能な設定になります。

.ssh以下に、鍵が生成されます。

Your identification has been saved in /home/username/.ssh/id_rsa.
Your public key has been saved in /home/username/.ssh/id_rsa.pub.
The key fingerprint is:
xx:xx:xx:xx:xx:xx:xxxx:xx:xx:xx:xx:xx:xx:xx username@hostname

id_rsaが公開鍵, id_rsa.pubが秘密鍵です。

2. 秘密鍵をリモートマシンへ配置

sshログインしたいリモートマシンに、先ほど作成した秘密鍵(id_rsa.pub)を配置します。

scp id_rsa.pub username@remote_host:.ssh
cat id_rsa.pub >> authorized_keys

リモートでも.ssh以下に送っておきます。送りつけたid_rsa.pubの内容を、authorized_keysに追記します。
以上で、パスワードを訊かれずにssh接続できるようになりました。Pythonスクリプトの中などからも1文でログインが可能です。

シェルスクリプトで配列へのpush/pop

配列listに値varをpush

n=${#list[@]}
list[$n]=$var

配列のサイズを添字として、新たな要素を追加しているだけ。シェルスクリプトの配列のインデックスは0からです。
問題は、popです。

配列listから値varをpop

n=`expr "${#list[@]}" - 1`
var=${list[$n]} 
unset list[$n]
list=${list[@]}

"unset"は、配列の指定した要素を削除します。しかし、同時にインデックスは削除されず、空要素として残ってしまいます。
そのため、最後に別の配列に入れ直して、リセットする必要があります。

ATNDで, 気になるイベントをメールで通知させる

今年は社外の勉強会に定期的に行く、と上司と1年前に約束したことをふと思い出し、最近になって勉強会に出向くようになりました。イベント探しによく利用するのはご存知ATNDです。
しかし、たまに思い出したときに気になるキーワードで検索をかけてみると、いい感じのイベントがすでに定員オーバーになっている、ということも少なくありません。
そこで、あらかじめ登録したキーワードにマッチするイベントを、メールで通知してくれるアプリを書いてみました。
ATNDのJava APIはここから落とせました。 => http://atnd4j.sourceforge.jp/
commonsのSimpleEmailを使って、Gmailsmtpサーバーから送ってます。

汚いけど許してね...

package jp.boc.com;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.hkzo.atnd4j.Atnd;
import org.hkzo.atnd4j.Event;
import org.hkzo.atnd4j.EventsResult;

public class EventNotifier {

	public static void main( String args[] ){

		EventNotifier ntfr = new EventNotifier();

		List<String> list = new ArrayList<String>();
		list.add( "kvs" );
		list.add( "nosql" );
		list.add( "デザインパターン" );

		String query = ntfr.createQuery( list );
		ntfr.sendMail( query );

	}

	private String createQuery( List<String> keywords ){

		StringBuffer sb = new StringBuffer();
		sb.append("keyword_or=");
		for ( String s : keywords ) {
			sb.append(s + "," );
		}
		return sb.toString();
	}

	private void sendMail ( String query ) {
		org.apache.commons.mail.SimpleEmail se = new SimpleEmail();
        try {
             se.setCharset( "utf-8" );
             se.setHostName( "smtp.gmail.com" );
             se.setSmtpPort( 587 );
             se.setTLS( true );
             se.setAuthentication( "username", "password" );
             se.addTo( "送り先アドレス" );
             se.setFrom( "gmailアドレス" );
             se.setSubject( "気になるATNDイベント" );

             StringBuilder msgBldr = new StringBuilder();
             for( Event event : getEvent( query ) ) {
            	 msgBldr.append( "★ " + event.getTitle() + " " + event.getStartedAt() + " @ " + event.getAddress() + "\n"  + "	" + event.getCatch() + "\n\n");
             }
             se.setMsg(msgBldr.toString());
             se.send();

        } catch ( EmailException eme ) {
        	eme.printStackTrace();
        }
	}

	private List<Event> getEvent( String query ) {

		  Atnd atnd = new Atnd();
		  EventsResult res = null;

		  try {
			  res = atnd.getEvents( query );
		  } catch ( IOException ioe ) {
			  ioe.printStackTrace();
		  }

		  List<Event> list = res.getEvents();
		  return list;

		 }
}

とこんな感じのものを、クーロンから3日に1回くらい叩きたいわけです。
問題は置いておくサーバがないということと、たった今、"ATND Notifier"という素晴らしいChrome Extensionを見つけてしまったため、このアプリの存在価値がなくなってしまったことでしょうか。。

Excel2007で簡単ヒストグラム

Excelでびっくりするほど簡単にヒストグラムが作成できます。とても便利なのに、知らんかった・・・のでメモ。

  • 準備(アドインのインストール)
    • Officeボタン > Excelのオプション > アドイン > 設定 > 分析ツール にチェックし、インストール
    • データタブに、「分析」カテゴリが登場する
  • 実行
    • 「分析」カテゴリの「データ分析」をクリック
    • ヒストグラム」をクリック
    • 「入力範囲」に対象データ範囲を指定
    • 「データ区間」(グラフの横軸にあたる)も指定可能だが、空欄だと入力範囲に合わせて等間隔で区間が刻まれる
    • グラフ作成 にチェックして、OKをクリックすると、別シートにグラフが生成されます

ありがとう、Excelさん。

expectで対話型シェル

sshやscpなど、対話型のインプットが必要なコマンドを、スクリプト化して運用に使いづらいので、expectパッケージを利用すると便利です。
OSにあらかじめexpectのパッケージが入っていない場合、下記コマンドでインストール。

yum install expect

下記は、リモートホストにログインして ls を叩くシェルのサンプルです。

#!/bin/bash

hostname=192.168.10.12
username=hoge
password=hogehoge

expect -c "
spawn ssh -l oracle $hostname
expect \"$username@$hostname's password:\" {
  send \"$password\n\"
} \"Are you sure you want to continue connecting (yes/no)?\" {
  send \"yes\n\"
  expect \"$username@$hostname's password:\"
  send \"$password\n\"
}

expect \"\[$username@$hostname ~\]$\"
send \"ls\n\"

interact
"

ポイントはこれだけ

  • spawn 最初に投げるコマンド(別プロセスを生成)
  • expect 予想される表示内容(パターンマッチが使える)
  • send 表示内容に対して送りたいコマンド(改行文字を忘れずに。)
  • expect "A" { send "B" } "A'" { send "B'" } と場合分けが可能

このサンプルでは、はじめてssh接続するホストの場合、~/.ssh/known_hosts に公開鍵登録の可否を聞かれるので、その表示が出るときと出ないときを場合分けしてます。

ROWNUMで結果のレコード数を制限する

あるカラムでソートした結果の、上位n件だけを抽出したい・・・というときに便利な
LIMIT句というものがあります。

select * from EMPLOYEES
order by EMPLOYEE_ID asc
limit 10;

これで、EMPLOYEE_IDのトップ10件のみ取得できます。
しかし、悲しいことにOracleではLIMIT句がサポートされていない・・・

代替として ROWNUM擬似列なるものを使って取得する必要があります。
ROWNUMとは、ある結果のセットに、仮想的なレコード番号を振ったものです。
このROWNUMを条件句にセットし、結果を制限します。

上記SQLと同様のことがしたい時は、以下のような感じになります。

select * from 
  ( select rownum rn, s.* from 
    ( select * from EMPLOYEES
      order by EMPLOYEE_ID
    ) s
  ) a
where a.rn <= 10 
order by a.rn;

注意点として、rownumは、直接where句やorder by句に指定できないので、
わざわざ入れ子にして別名をつける必要あり。ジャマくさいわね。