dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

duコマンドで出力結果のディレクトリ階層数を指定する方法

2011-04-29 17:09:36 | linux
du コマンドで --max-depth オプションを指定すると、ファイル容量を指定の階層数までにまとめて出力してくれます。

$ du -m /usr --max-depth=1
1 /usr/X11R6
145 /usr/bin
1 /usr/etc
1 /usr/games
86 /usr/include
...


--max-depth 指定がない場合には全ディレクトリ毎に容量を表示します。

$ du -m /usr
...
1 /usr/lib/locale/aa_DJ.utf8/LC_MESSAGES
2 /usr/lib/locale/aa_DJ.utf8
1 /usr/lib/locale/aa_DJ/LC_MESSAGES
1 /usr/lib/locale/aa_DJ
...

wgetでレスポンスヘッダを取得する方法

2011-04-28 23:20:38 | linux
wgetでレスポンスヘッダを取得するには --server-response オプションを指定します。

$ wget -O - 'http://www.goo.ne.jp/' --server-response

ただし、レスポンスヘッダは stderr に出力されます。

wgetでBasic認証があるページにアクセスする方法

2011-04-27 21:49:11 | linux
wgetでBasic認証があるページにアクセスするには、
--http-userでユーザ名、--http-passwdでパスワードを指定します。

$ wget -O - 'http://www.goo.ne.jp/' --http-user=user_id --http-passwd=password

wgetでUserAgentを指定する方法

2011-04-26 23:32:40 | linux
wgetでUserAgentを指定する場合には、--user-agent オプションを使います。

$ wget -O - 'http://blog.goo.ne.jp/' --user-agent='DoCoMo/2.0 F-06C'

wgetでproxyを指定する方法

2011-04-26 01:03:05 | linux
wgetでproxy経由でHTMLを取得するには、コマンドラインオプションで -e HTTP_PROXY={proxyホスト名} を指定します。

$ wget -e HTTP_PROXY=proxy.co.jp 'http://www.goo.ne.jp/'

ポート番号を指定する場合には、proxyホスト名の後ろに ":{ポート番号}" を追加します。

$wget -e HTTP_PROXY=proxy.co.jp:8080 'http://www.goo.ne.jp/'



mysqldumpでデータのみ/テーブル定義のみをダンプする方法

2011-04-20 22:16:53 | mysql
mysqldumpをオプションなしで実行すると、標準出力にテーブル定義のcreate文とinsert文が出力されます。

insert文だけを出力するには、-t または --no-create-info オプションを指定します。
$ mysqldump -t DB名 テーブル名

テーブル定義だけを出力するには -d または --no-data オプションを指定します。
$ mysqldump -d DB名 テーブル名

テーブル定義だけを出力する方法として、-w でダンプするデータの条件が偽になるようにするという手もあります。
$ mysqldump DB名 テーブル名 -w '0=1'

さらに意味のない方法ですが、show create table を使って create 文を出力することもできます。
show create table は以下のようにテーブル定義を出力します。

mysql> show create table id;
+-------+---------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+---------------------------------------------------------------------------------------------+
| id | CREATE TABLE `id` (
`id` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+-------+---------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

-s でカラム名を抑制し、-r でエスケープ文字をそのまま出力するようにして、2カラム目だけを cut コマンドで出力します。
$ echo "show create table テーブル名;" | mysql DB名 -s -r
CREATE TABLE `id` (
`id` varchar(255) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

mysqldump -d を使えば、こんな面倒なことはしなくていいんですが。


rubyでflockを使った排他制御(その2)

2011-04-19 00:17:44 | ruby
先日の『rubyでflockを使った排他制御』では、排他されているプロセスはずっと待ち状態になってしまいます。
そのため、いくつかのプロセスが常に動作している環境では、ずっと待ち状態になってしまう可能性があります。

ブロックされている場合の処理を記述したい場合には、flock の引数に File::LOCK_NB を指定します。

■プログラム例
#!/usr/local/bin/ruby
#
# flock による排他制御
# usage: flock_nb.rb {ID} {retry} {interval}
#

$KCODE = 'u'
require 'jcode'
require 'time'

# lock
# @param lockfile
# @param num_retry リトライ回数
# @param interval リトライ間隔
# @return lockfileのstream / nil
def lock(lockfile, num_retry, interval)
st = File.open(lockfile, 'a')
if ! st
STDERR.print("failed to open\n")
return nil
end

0.upto(num_retry) do |i|
begin
res = st.flock(File::LOCK_EX | File::LOCK_NB)
return st if res

print("[#{Time.now().to_s}] sleep [#{ARGV[0]}]\n")
sleep(interval)
rescue
STDERR.print("failed to lock\n")
return nil
end
end

return nil
end

# unlock
# @param lockfile
# @return true / false
def unlock(st)
begin
st.flock(File::LOCK_UN)
st.close
rescue
STDERR.print("failed to unlock")
return false
end

return true
end

sleep(5)

lock_st = lock('lockfile', ARGV[1].to_f, ARGV[2].to_f)
if ! lock_st
print("[#{Time.now().to_s}] failed to lock [#{ARGV[0]}]\n")
exit
end

print("[#{Time.now().to_s}] get lock [#{ARGV[0]}]\n")
sleep(10)
print("[#{Time.now().to_s}] release lock [#{ARGV[0]}]\n")

unlock(lock_st)

■実行結果
$ ./flock_nb.rb 1 3 3 &
$ ./flock_nb.rb 2 3 3 &
$ ./flock_nb.rb 3 3 3 &
[Tue Apr 19 00:15:43 +0900 2011] get lock [1]
[Tue Apr 19 00:15:46 +0900 2011] sleep [2]
[Tue Apr 19 00:15:48 +0900 2011] sleep [3]
[Tue Apr 19 00:15:49 +0900 2011] sleep [2]
[Tue Apr 19 00:15:51 +0900 2011] sleep [3]
[Tue Apr 19 00:15:52 +0900 2011] sleep [2]
[Tue Apr 19 00:15:53 +0900 2011] release lock [1]
[Tue Apr 19 00:15:54 +0900 2011] get lock [3]
[Tue Apr 19 00:15:55 +0900 2011] sleep [2]
[Tue Apr 19 00:15:58 +0900 2011] failed to lock [2]
[Tue Apr 19 00:16:04 +0900 2011] release lock [3]




rubyでflockを使った排他制御

2011-04-16 21:30:01 | ruby
rubyでプロセス間で排他制御を行うのに、一番最初に思いつくのはロックファイルを作成する方法でしょう。
ロックファイルを使う方法では、ロックファイルがある場合にはsleepして、再びロックファイルの存在をチェックし、ロックファイルがない場合にはロックファイルを作成します。

しかし、ロックファイルの作成後にエラーが発生して、ロックファイルはあってもロックをかけたプロセスが異常終了した場合には、ロックファイルが残ったままになって、他のプロセスがロックを獲得できなくなってしまいます。
ロックファイルにプロセスIDを書き込んでおけば、ロックファイルに記述されたプロセスIDが存在しないことをチェックできるので、エラー処理に役立ちますが、少し面倒ではないでしょうか。

File#flockを使って排他制御を行うと、以下の理由でプログラムが少し楽になるでしょうか。
・ruby インタプリタが終了した場合にロックが解除されるため、ロックファイルを削除する必要がない。
・排他ロックを実行すると、ロックが解除されるまでプロセスが待機状態になり、ロックが解除されればロックを獲得できます。
sleepして、再度ロックファイルをチェックするような処理は不要です。

■プログラム

#!/usr/local/bin/ruby
#
# flock による排他制御
#
# usage: flock.rb {ID}

$KCODE = 'u'
require 'jcode'
require 'time'

# 指定ファイルでロック
# @param lockfile
# @return lockfileのstream / nil
def lock(lockfile)
st = File.open(lockfile, 'a')
if ! st
STDERR.print("failed to open\n")
return nil
end

begin
st.flock(File::LOCK_EX)
rescue
STDERR.print("failed to lock\n")
return nil
end

return st
end

# アンロック
# @param st
# @return true / false
def unlock(st)
begin
st.flock(File::LOCK_UN)
st.close
rescue
STDERR.print("failed to unlock")
return false
end

return true
end

sleep(5)

# ロック
lock_st = lock('lockfile')

# 排他制御
print("[#{Time.now().to_s}] get lock [#{ARGV[0]}]\n")
sleep(10)
print("[#{Time.now().to_s}] release lock [#{ARGV[0]}]\n")

# アンロック
unlock(lock_st)

■実行結果
$ ./flock.rb 1&
$ ./flock.rb 2&
$ ./flock.rb 3&
[Sat Apr 16 21:26:33 +0900 2011] get lock [1]
[Sat Apr 16 21:26:43 +0900 2011] release lock [1]
[Sat Apr 16 21:26:43 +0900 2011] get lock [2]
[Sat Apr 16 21:26:53 +0900 2011] release lock [2]
[Sat Apr 16 21:26:53 +0900 2011] get lock [3]
[Sat Apr 16 21:27:03 +0900 2011] release lock [3]

rubyのCGIでプロファイルをとる方法

2011-04-15 01:52:34 | ruby
コマンドラインで ruby プログラムのプロファイルをとるには、以下のように -r profile を指定します。
(-r と profile の間の空白文字は無くてもかまいません)

$ ruby -r profile {プログラム名}

プロファイル結果は標準エラーに出力されます。


CGI の場合には、CGIの先頭行で以下を記述します。
-r と profile の間に空白があるとエラーになります。

#!/usr/local/bin/ruby -rprofile

プロファイル結果はコマンドラインでは標準エラーに出力されていたので、CGI ではプロファイル結果は /var/log/httpd/error_log.YYYYMMDD に出力されます。

rubyのhashでmax

2011-04-10 23:32:45 | ruby
rubyのhashで、値の最大値を取得する方法です。

$ irb
irb(main):001:0> h = { 'a' => 10, 'b' => 100, 'c' => 50 }
=> {"a"=>10, "b"=>100, "c"=>50}

irb(main):002:0> h.max { |a, b| a[1] <=> b[1] }
=> ["b", 100]

値が最大のキーと値のペアの配列が取得できます。
配列ですので、以下のようにすれば、キーまたは値だけを取得することもできます。

irb(main):003:0> (h.max { |a, b| a[1] <=> b[1] })[0]
=> "b"

irb(main):004:0> (h.max { |a, b| a[1] <=> b[1] })[1]
=> 100

ちなみに、キーの最大値を取得するなら、以下のようにします。
irb(main):005:0> h.max { |a, b| a[0] <=> b[0] }
=> ["c", 50]

mysqlコマンドの検索結果で文字列をエスケープしない方法

2011-04-07 23:05:23 | mysql
mysqlコマンドの標準入力に select 文を流すと、テキスト系カラムの検索結果は、文字列がエスケープされます。

$ cat sel.sql
select * from txt;

$ cat sel.sql | mysql test
txt
abc\tdef
1\n2\n3\n

検索結果の文字列がエスケープされないようにするには mysql コマンドに -r または --raw を指定します。

$ cat sel.sql | mysql -r test
txt
abc def
1
2
3


mysqlでテーブルのレコード数を確認する方法

2011-04-06 21:53:15 | mysql
mysqlでテーブルのレコード数を取得する方法です。
select count(*) from テーブル名 でもよいのですが、たとえばDBの全テーブルのレコード数を知りたい場合には、テーブル数だけ select を実行しなければならなくなります。

こんな場合には、mysqlのテーブル情報でも書いた information_schema DB の TABLES テーブルから情報を取得します。

> select table_name, table_rows from information_schema.TABLES;

+------------+------------+
| table_name | table_rows |
+------------+------------+
| tbl1 | 10 |
| tbl2 | 5 |
| tbl3 | 5 |
+------------+------------+
3 rows in set (0.00 sec)

これだと全DBのテーブル情報を取得してしまうので、特定のDBのテーブルのレコード数を取得するには、where table_schema = 'DB名' で対象とする DB を指定します。

select table_name, table_rows from information_schema.TABLES
where table_schema = 'DB名';







mysqlのgroup_concat

2011-04-05 23:37:14 | mysql
mysqlで、行毎の文字列データを連結するには、group_concat を使います。

■テーブル定義
drop table if exists id;
create table id (
id varchar(255)
);

insert into id set id = 'id1';
insert into id set id = 'id2';

drop table if exists score;
create table score (
id varchar(255),
subject varchar(16),
score int
);

insert into score set id = 'id1', subject = 'math', score = '90';
insert into score set id = 'id1', subject = 'sci', score = '80';
insert into score set id = 'id1', subject = 'eng', score = '70';
insert into score set id = 'id2', subject = 'math', score = '100';

■select文
select
i.id as id
, group_concat(s.subject, ',', s.score order by subject separator ',') \
as scores
from
id i
, score s
where
i.id = s.id
group by
i.id
order by
i.id
;

■検索の実行結果
id scores
id1 eng,70,math,90,sci,80
id2 math,100

プロセスの生死を確認する方法

2011-04-03 21:59:58 | linux
kill -0(ゼロ) PID で、指定プロセスの生死を確認することができます。

$ sleep 30&
[1] 12858

30秒間スリープする。sleep のプロセスIDは 12858。
30秒経過する前に kill -0 12858 を実行すると、kill コマンドの終了ステータスは 0 になります。

$ kill -0 12858; echo $?
0

sleep コマンド終了後に kill -0 12858 を実行すると、

$ kill -0 12858; echo $?
-bash: kill: (12858) - そのようなプロセスはありません
1

終了コードは 1 になっているので、kill -0 PID でプロセスの生死を確認することができます。