Vista ではコマンドプロンプトにドラッグ&ドロップできない

Windows Vista では XP までのように ファイルをコマンドプロンプトにドラッグ&ドロップして ファイルのパスを貼ることができません。

方法が無いかと検索してみると次のような記事がありました。

【参考サイト】
ここが変わったWindows Vista 100連発! ― 第49回 “パスとしてコピー”でコマンドプロンプトにパス名を渡す

これによると Vista では [Shift] キーを押しながら右クリックすると 次のように「パスとしてコピー」するメニューが出てくるので これでファイルのパスをコピーしてから コマンドプロンプトに貼り付けるそうです。

WRITE_0275_01

ドラッグ&ドロップが便利だったので残念です。

PostgreSQL の ANALYZE の動きを確認する

前回 VACUUM の確認について書きましたが 今回は ANALYZE の確認について書きたいと思います。

まずはテーブル analyze_test を作成します。

db=# CREATE TABLE analyze_test (f1 VARCHAR(10), f2 INTEGER);
CREATE TABLE

ANALYZE も情報を pg_stat_all_tables から取得できます。

db=# SELECT * FROM pg_stat_all_tables
db-# WHERE relname = 'analyze_test';

-[ RECORD 1 ]----+------------------------------
relid            | 16469
schemaname       | public
relname          | analyze_test
seq_scan         | 2
seq_tup_read     | 9
idx_scan         |
idx_tup_fetch    |
n_tup_ins        | 5
n_tup_upd        | 1
n_tup_del        | 1
n_tup_hot_upd    | 1
n_live_tup       | 4
n_dead_tup       | 0
last_vacuum      |
last_autovacuum  |
last_analyze     |
last_autoanalyze |

ANALYZE する前はこのような状態です。

また、pg_stat_all_tables の他に 列ごとの統計情報が pg_stats ビューから取得できます。

db=# SELECT * FROM pg_stats WHERE tablename = 'analyze_test';
(No rows)

ANALYZE する前は レコードが取得できません。

それでは ANALYZE を実行します。

db=# ANALYZE analyze_test;
ANALYZE

状態を確認します。

db=# SELECT * FROM pg_stat_all_tables
db-# WHERE relname = 'analyze_test';

-[ RECORD 1 ]----+------------------------------
relid            | 16469
schemaname       | public
relname          | analyze_test
seq_scan         | 2
seq_tup_read     | 9
idx_scan         |
idx_tup_fetch    |
n_tup_ins        | 5
n_tup_upd        | 1
n_tup_del        | 1
n_tup_hot_upd    | 1
n_live_tup       | 4
n_dead_tup       | 0
last_vacuum      |
last_autovacuum  |
last_analyze     | 2010-04-24 15:49:12.383112+09
last_autoanalyze |

last_analyze に ANALYZE した時刻が格納されました。

列ごとの統計情報を確認します。

db=# SELECT * from pg_stats WHERE tablename = 'analyze_test';

-[ RECORD 1 ]-----+--------------------------
schemaname        | public
tablename         | analyze_test
attname           | f1
null_frac         | 0
avg_width         | 6
n_distinct        | -1
most_common_vals  |
most_common_freqs |
histogram_bounds  | {00001,00003,00004,00005}
correlation       | -0.2
-[ RECORD 2 ]-----+--------------------------
schemaname        | public
tablename         | analyze_test
attname           | f2
null_frac         | 0
avg_width         | 4
n_distinct        | -1
most_common_vals  |
most_common_freqs |
histogram_bounds  | {15,30,40,50}
correlation       | -0.2

ANALYZE したテーブルの列のレコードが追加されています。

histogram_bounds に列の値のサンプルが入っています。
(行が少ないので全ての値が入っています)

PostgreSQL の VACUUM の動きを確認する

PostgreSQL は データを更新したときや 削除したときに レコードに「不要」マークを付けるという処理を行ないます。

「不要」マークの付いたレコード(以下、不要なレコード)は そのままでは再利用できないのでデータを挿入しなくても 更新を繰り返すだけで テーブルの使用するスペースは広がっていきます。

VACUUM は、不要になったレコードのスペースを 再利用可能にします。 今回は、その動きを確認してみたいと思います。

まずは新しくテーブル vacuum_test を作成します。

db=# CREATE TABLE vacuum_test (f1 VARCHAR(10), f2 INTEGER);
CREATE TABLE

情報は pg_stat_all_tables カタログから取得します。

db=# SELECT n_live_tup,n_dead_tup,last_vacuum,last_autovacuum
db-# FROM pg_stat_all_tables
db-# WHERE relname = 'vacuum_test';

-[ RECORD 1 ]----+------------
n_live_tup       | 0
n_dead_tup       | 0
last_vacuum      |
last_autovacuum  |

テーブルを作成した時点では上のようになっています。

VACUUM に関連する主な列のみ取得しています。
それぞれの列の意味は次のようになります。

列名 説明
n_live_tup 有効なレコード数
n_dead_tup 不要になったレコード数
last_vacuum 最後に VACUUM を実行した時刻
last_autovacuum 最後に 自動 VACUUM が実行された時刻

レコードを挿入します。

INSERT INTO vacuum_test VALUES ('00001', 10);
INSERT INTO vacuum_test VALUES ('00002', 20);
INSERT INTO vacuum_test VALUES ('00003', 30);
INSERT INTO vacuum_test VALUES ('00004', 40);
INSERT INTO vacuum_test VALUES ('00005', 50);

状態を確認します。

db=# SELECT n_live_tup,n_dead_tup,last_vacuum,last_autovacuum
db-# FROM pg_stat_all_tables
db-# WHERE relname = 'vacuum_test';

-[ RECORD 1 ]----+------------
n_live_tup       | 5
n_dead_tup       | 0
last_vacuum      |
last_autovacuum  |

5 レコード挿入したので、有効なレコード数が 5 になりました。

次に 1 レコード削除します。

db=# DELETE FROM vacuum_test WHERE f1 = '00002';
DELETE 1

状態を確認します。

db=# SELECT n_live_tup,n_dead_tup,last_vacuum,last_autovacuum
db-# FROM pg_stat_all_tables
db-# WHERE relname = 'vacuum_test';

-[ RECORD 1 ]----+------------
n_live_tup       | 4
n_dead_tup       | 1
last_vacuum      |
last_autovacuum  |

有効なレコード数が 4 になり 不要なレコード数が 1 になりました。

ついでに更新もします。

db=# UPDATE vacuum_test SET f2 = 15 WHERE f1 = '00001';
UPDATE 1

しつこく状態を確認します。

db=# SELECT n_live_tup,n_dead_tup,last_vacuum,last_autovacuum
db-# FROM pg_stat_all_tables
db-# WHERE relname = 'vacuum_test';

-[ RECORD 1 ]----+------------
n_live_tup       | 4
n_dead_tup       | 2
last_vacuum      |
last_autovacuum  |

不要なレコード数が 1 増えました。

ここまでは準備です。 ようやく VACUUM を実行します。

db=# VACUUM vacuum_test;
VACUUM

状態を確認します。

db=# SELECT n_live_tup,n_dead_tup,last_vacuum,last_autovacuum
db-# FROM pg_stat_all_tables
db-# WHERE relname = 'vacuum_test';

-[ RECORD 1 ]----+------------------------------
n_live_tup       | 4
n_dead_tup       | 0
last_vacuum      | 2010-04-20 22:20:20.560647+09
last_autovacuum  | 

不要なレコード数が 0 になりました。
last_vacuum に VACUUM を実行した時刻が入っています。

このように VACUUM で、不要になったレコードの スペースを再利用可能にすることができます。

パスワードを一括で変更する

Linux には パスワードを一括で変更できる chpasswd というコマンドがあります。 使い方は簡単で標準入力からユーザ名とパスワードのセットを渡すだけです。

例えば testuser1 のパスワードを hogehoge にする場合 次のように ユーザ名とパスワードをコロンで区切ってパイプします。

# echo "testuser1:hogehoge" | chpasswd

複数ユーザのパスワードを一括で変更する場合 次のように ファイルにユーザ名とパスワードのセットを記述します。

# vi passwd.txt
testuser1:hogehoge1
testuser2:hogehoge2
testuser3:hogehoge3

これをパイプで渡します。

# cat passwd.txt | chpasswd

全ユーザのパスワードを一括で初期化する場合など便利です。

Bash で 配列を使ってみる その 2

前回( Bash で 配列を使ってみる その 1 )は値の格納でしたが 今回は配列らしく for ループを使って値を出力します。

まずは 普通の? for 文です。 配列の値を全て出力するには次のように 添え字に "@" か "*" を使います。

$ ARRAY=(one two three four)

$ echo ${ARRAY[@]}
one two three four

$ echo ${ARRAY[*]}
one two three four

これを for 文で使用します。

$ ARRAY=(one two three four)

$ for item in ${ARRAY[@]}
> do
>     echo $item
> done
one
two
three
four

ただし、これは 1 つ問題があります。

Bash の for 文 その 2 で書きましたが for 文は IFS (デフォルトはスペースなど) で区切られた文字列でループさせることができるので 配列の要素が IFS を含む文字列の場合、次のようにループが増えてしまいます。

$ ARRAY=("one1 one2 one3" two three four)

$ echo ${ARRAY[0]}
one1 one2 one3

$ for item in ${ARRAY[@]}
> do
>     echo $item
> done
one1
one2
one3
two
three
four

これを防ぐためにプログラム言語のような for 文を使用します。

配列の添え字の最大を取得するには次のようにします。

$ ARRAY=("one1 one2 one3" two three four)

$ echo ${#ARRAY[@]}
4

$ echo ${#ARRAY[*]}
4

これを for 文で使用します。

$ ARRAY=("one1 one2 one3" two three four)

$ for (( i = 0; i < ${#ARRAY[@]}; i++ ))
> do
>     echo ${ARRAY[$i]}
> done
one1 one2 one3
two
three
four

1 つめの配列も正しく出力されました。

Bash で 配列を使ってみる その 1

まずは値の格納です。 直接 1 つずつ指定する方法です。

$ A[0]=one
$ A[1]=two

もう一つは一括で指定する方法です。

$ A=(one two three four)

配列の値を出力するには "{}" (ブランケット)を 使用する必要があります。

$ echo ${A[0]}

ブランケットを指定しないと 変数 "$A" と "[0]" という文字の出力になってしまいます。

ちなみに 次のように添え字 0 の値は 添え字を指定しない変数の値と同じになります。

$ echo ${A[0]}
one

$ echo $A
one

ですのでブランケットを使用しない場合は次のように出力されます。

$ echo $A[0]
one[0]

IFS (Internal Field Separator) の値を表示する

Bash の for 文 その 2 で IFS を出したんですが、 デフォルトの IFS の中身を表示することができないかなと 考えていました。

普通に出力しても次のようになってしまいます。

$ echo "[$IFS]"

[
]

次のサイトに良い方法が載っていました。

【参考サイト】
IFS - http://www.curri.miyakyo-u.ac.jp/pub/doc/sh/node31.html

$ echo -n "$IFS" | od -b

0000000 040 011 012
0000003

$ echo -n "$IFS" | od -c

0000000      \t  \n
0000003

040 011 012 は 8進数です。
値としては スペース(0x20)、水平タブ(0x09)、改行(0x0A)になります。

Bash の for 文 その 2

Bash の for 文 の続きです。

文字列内のリスト

次のように文字列の空白で区切られた項目をリストとして ループさせることができます。

$ ITEMS="one two three four"

$ for item in $ITEMS
> do
>     echo $item;
> done;

one
two
three
four

正しくは空白ではなく IFS (Internal Field Separator) で定義されているもので 文字列を分割します。 IFS を変更すると区切りを変えることができます。

$ ITEMS="one/two/three four"
$ IFS="/"

$ for item in $ITEMS
> do
>     echo $item;
> done;

one
two
three four

引数のリスト

他に引数のリストでループさせるというのもあります。

$ function test () {
>     for item in $*
>     do
>         echo $item;
>     done;
> }

$ test one two three four

one
two
three
four

Bash の for 文

Bash で使える for 文には色々な形があります。

候補のリスト

$ for item in one two three four
> do
>     echo $item
> done

one
two
three
four

in の後に並べた値をループさせます。

ディレクトリ・ファイルのリスト

$ for item in /tmp/*
> do
>     echo $item
> done

/tmp/aaaa.txt
/tmp/bbbb.txt

マッチする ディレクトリやファイルのパスでループさせます。

コマンドの結果のリスト

$ for item in $(wc /tmp/a.txt)
> do
>     echo $item
> done

0
3
9

コマンド置換を使って、実行結果でループさせます。

これを利用して seq コマンドを使う方法があります。

$ for item in $(seq 1 3)
> do
>     echo $item
> done

1
2
3

Java などの言語によくある for 文

言語でよくみかける 初期条件や繰り返し条件が セミコロンで区切られてる形式も使えます。

$ for (( item = 0; item < 3; item++ ))
> do
>     echo $item
> done

0
1
2

二重カッコ (()) を使います。

Google サイト内検索

Amazonアソシエイト