2012年12月22日土曜日

findとgrepコマンドを組み合わせて全文検索


複数ファイルの中身をまとめて検索するコマンドの組み合わせです。findコマンドの
結果をxargsを利用してgrepコマンドに渡し、キーワードとマッチしたファイルおよび
該当行を出力させることが可能です。

情報が古くなった等でWebページを削除する場合、そのページにリンクしている他の
ページを探し出してリンク切れを防止したい時にも使えそうです。

OS: CentOS 6.3(64-bit)
find: 4.4.2
grep: 2.6.3


■サンプルデータを準備

検索対象のHTMLファイル数を確認
[root@cent63 sample_data]# find . -type f | grep .html$ | wc -l 1127

■適当なキーワードで全文検索

キーワード「charset」にマッチしたしたファイル名と、その行数を出力
grepの「-n」オプションで該当行を出力させることができます。
[root@cent63 sample_data]# find . -type f | grep .html$ | xargs grep -n "charset" ./planning/file07_01_01_00095.html:5:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ./planning/keikan01_001032.html:5:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ./planning/index10_14.html:5:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ./planning/file08_02_00033.html:5:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ./planning/file07_00001.html:5:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ./planning/gikai01_001013.html:5:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> (以下省略)

もちろん日本語でも検索可能(対象のcharsetがUTF-8であれば)
[root@cent63 sample_data]# time find . -type f | grep .html$ | xargs grep -n "まちづくり" | wc -l 1810 real 0m0.093s user 0m0.052s sys 0m0.039s [root@cent63 sample_data]#
検索対象が1000ファイルくらいあっても1秒以下で検索可能でした。

■他のファイルからリンクされているかを調査

とりあえず対象ファイル数を調べた後、そのリストを表示させる。
[root@cent63 sample_data]# find . -type f | grep .html$ | xargs grep file08_00023.html | wc -l 6 [root@cent63 sample_data]# find . -type f | grep .html$ | xargs grep -l file08_00023.html ./planning/file08_00023.html ./planning/index08.html ./planning/index.html ./planning/file08_00015.html [root@cent63 sample_data]#

リンク切れ修正対象個所を表示
[root@cent63 sample_data]# find . -type f | grep .html$ | xargs grep -n file08_00023.html ./planning/file08_00023.html:84:<p><a href="/index.html">緑区ホーム</a> > <a href="/planning/index.html">区政情報</a> > <a href="/planning/index08.html">緑区議会</a> > <a href="/planning/file08_00023.html">インターネット中継</a> > 区議会のインターネット中継について</p> ./planning/file08_00023.html:243: <input name="email" type="hidden"> <input name="code" type="hidden" value="110100"> <input name="pgid" type="hidden" value="000005064"> ./planning/index08.html:132:<li class="arrow"><a href="/planning/file08_00023.html">予算特別委員会(7月11日)の録画中継を公開しました</a>[2012年7月19日]</li> ./planning/index08.html:142:<li class="parent"><a href="/planning/file08_05_00016.html">区議会からのお知らせ</a></li><li class="parent"><a href="/planning/index08_07.html">議会日程</a></li><li class="parent"><a href="/planning/file08_00023.html">インターネット中継</a></li><li class="child clearfix"> ./planning/index.html:153:<dl><dt class="dir1"><a href="/planning/file08_00023.html">インターネット中継</a></dt></dl> ./planning/file08_00015.html:134:<li class="arrow"><a href="/planning/file08_00023.html">インターネット中継</a><p>本会議と予算・決算特別委員会は、インターネット中継(生中継・録画中継)をしています。</p></li> [root@cent63 sample_data]#
※表示の都合上タグを"<"と">"で記載。

以上です。何かのお役にたてれば幸いです。

2012年12月4日火曜日

PerlのCGIでよくお目見えするInternal Server Error 解決法


PerlのCGIでフォームからpostでデータ取得するサンプルです。
とりあえずhttpdをインストールするあたりから記載していますが、
必要なところから参考にしていただければ。

Amazon Linux の場合、CGI.pmがないのでインストールする手順も記載していますが、
CentOSならおそらくデフォルトインストールされているのでその手順は不要です。

Internal Server Error を発生させその解決法も併せて記載しています。

■構成情報
・OS: Amazon Linux AMI release 2012.09(64bit)
・Perl: 5.10.1


■httpdインストール
[root@ip-10-77-30-12 ~]# yum -y install httpd
(中略)
===========================================================================
 Package              Arch       Version              Repository      Size
===========================================================================
Installing:
 httpd                x86_64     2.2.23-1.25.amzn1    amzn-updates   1.2 M
Installing for dependencies:
 apr                  x86_64     1.4.6-1.10.amzn1     amzn-main      110 k
 apr-util             x86_64     1.4.1-4.13.amzn1     amzn-main       87 k
 apr-util-ldap        x86_64     1.4.1-4.13.amzn1     amzn-main       17 k
 generic-logos        noarch     16.0.0-1.4.amzn1     amzn-main      588 k
 httpd-tools          x86_64     2.2.23-1.25.amzn1    amzn-updates    75 k

Transaction Summary
===========================================================================
(省略)

■CGI動作設定
[root@ip-10-77-30-12 ~]# cd /etc/httpd/conf/
[root@ip-10-77-30-12 conf]# cp -p httpd.conf httpd.conf.org
[root@ip-10-77-30-12 conf]# vi httpd.conf
[root@ip-10-77-30-12 conf]# diff httpd.conf httpd.conf.org
797c797
< AddHandler cgi-script .cgi
---
> #AddHandler cgi-script .cgi
[root@ip-10-77-30-12 conf]#

■サンプルhtml(radio.html)作成
htmlプログラムは表示上の都合のため画像でご勘弁を。

■サンプルcgi(radio.cgi)プログラム作成
[root@ip-10-77-30-12 ~]# vi /var/www/cgi-bin/radio.cgi
[root@ip-10-77-30-12 ~]# cat /var/www/cgi-bin/radio.cgi
#!/usr/bin/perl

use CGI;
$form_data = new CGI;

$goods = $form_data->param('goods');

print "Content-type: text/html\n\n";
print "\n";
print "$goods が購入されました。\n";
print "\n";
[root@ip-10-77-30-12 ~]#

■cgiプログラムテスト実行
[root@ip-10-77-30-12 ~]# perl /var/www/cgi-bin/radio.cgi
Can't locate CGI.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /var/www/cgi-bin/radio.cgi line 3.
BEGIN failed--compilation aborted at /var/www/cgi-bin/radio.cgi line 3.
[root@ip-10-77-30-12 ~]#
エラー発生。
perlモジュールとしてCGI.pmがインストールされているか調査
[root@ip-10-77-30-12 ~]# find `perl -e 'print "@INC"'` -name '*.pm' -print | grep CGI
find: `/usr/local/lib64/perl5': No such file or directory
find: `/usr/local/share/perl5': No such file or directory
[root@ip-10-77-30-12 ~]#
ないのね…。

■CGI.pmインストール
[root@ip-10-77-30-12 ~]# yum -y install perl-CGI
(中略)
 Package        Arch         Version               Repository     Size
=======================================================================
Installing:
 perl-CGI       x86_64       3.51-127.15.amzn1     amzn-main     216 k

Transaction Summary
=======================================================================
Install       1 Package(s)

Total download size: 216 k
Installed size: 434 k
Downloading Packages:
perl-CGI-3.51-127.15.amzn1.x86_64.rpm                | 216 kB     00:00
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : perl-CGI-3.51-127.15.amzn1.x86_64                    1/1
  Verifying  : perl-CGI-3.51-127.15.amzn1.x86_64                    1/1

Installed:
  perl-CGI.x86_64 0:3.51-127.15.amzn1

Complete!
[root@ip-10-77-30-12 ~]#

■cgiプログラム再テスト
[root@ip-10-77-30-12 ~]# perl /var/www/cgi-bin/radio.cgi
Content-type: text/html

<body>
 が購入されました。
</body>
[root@ip-10-77-30-12 ~]#
エラーは解消。

■ブラウザで動作確認
CGIを実行させると…、
Internal Server Error キター!(T-T)
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator, root@localhost and inform them of the time the error occurred, and anything you might have done that may have caused the error.

More information about this error may be available in the server error log.

------------------------------------------------------------------------

Apache/2.2.23 (Amazon) Server at 54.xxx.xxx.xxx Port 80
原因はradio.cgiファイルに実行権がないためです。

■実行権追加
[root@ip-10-77-30-12 ~]# chmod 755 /var/www/cgi-bin/radio.cgi
もう一度ブラウザから同じようにCGIを実行させると・・・、
上記のように正しく表示されました。

■ Content-type: text/htmlも大事
下記のように「Content-type: text/html」を出力し忘れたcgiプログラムを作成すると、
[root@ip-10-77-30-12 ~]# vi /var/www/cgi-bin/radio.cgi
[root@ip-10-77-30-12 ~]# cat /var/www/cgi-bin/radio.cgi
#!/usr/bin/perl

use CGI;
$form_data = new CGI;

$goods = $form_data->param('goods');

print "\n";
print "$goods が購入されました。\n";
print "\n";
[root@ip-10-77-30-12 ~]#
期待通り?Internal Server Errorが出現しますのでお忘れなく。

2012年12月2日日曜日

CSVファイルを2次元配列に読み込むperlサンプル


自動販売機の在庫管理を例としてCSVファイルを2次元配列に読み込むperlサンプルです。
まずは行ごとに1次元配列(@csv_array)に読み込み、各行の要素は一度(@line)配列に保持し、
split関数を使用して2次元配列(@line_data)に読み込んでいます。

配列に読み込んだ後の処理は適当です。

配列をCSVファイルに出力する準備として2次元配列(@line_data)をjoin関数を使用して
カンマ区切りの要素とした1次元配列(@line_consolidate)に整形した後に
CSVファイルに出力しています。

■構成情報
・OS: Amazon Linux AMI release 2012.09(64bit)
・Perl: 5.10.1


■読み込むCSVファイル(goods.csv)
商品名,価格,在庫 ファンタ,100,28 キリンレモン,110,24 ポカリスエット,150,31 十六茶,130,18 アクエリアス,140,26 午後の紅茶,160,17 伊右衛門,140,19

■Perlプログラム(inoutcsv.pl)
#!/usr/bin/perl # csvファイルの内容を配列に読み込み、 # 配列の内容をcsvファイルに出力するサンプル ### 読み込みファイル $INPUT = "./goods.csv"; ### 出力ファイル $OUTPUT = "./goods.csv"; ### 配列の中身を初期化 my @csv_array = (); my @line = (); my @line_data = (); my @line_consolidate = (); ### csvファイルの中身を配列に読み込む open (FH, "$INPUT") or die "$!"; @csv_array = ; close (FH); # 要素を各配列に格納 print "要素を配列に格納\n"; print "----------------------\n"; my $i = 0; while ($i <= $#csv_array) { chomp ($csv_array[$i]); @line = split (/,/, $csv_array[$i]); my $j = 0; while ($j <= $#line) { $line_data[$i][$j] = $line[$j]; print "$i行$j番目の要素: $line_data[$i][$j]\n"; $j ++; } $i ++; } print "----------------------\n\n"; ### 商品購入処理 # 何らかの処理がされないと面白くないのでランダムに在庫を減らしています。 # 1行目はヘッダ行なので出力されないように制御。 my $dec = int(rand($#csv_array -1)) + 1; $line_data[$dec][2] = $line_data[$dec][2] -1; print "処理対象行: $dec $line_data[$dec][0]の在庫更新: $line_data[$dec][2]\n\n"; ### csvファイル出力用に配列を整形 print "csvに出力する内容を確認\n"; print "----------------------\n"; $i = 0; while ($i <= $#csv_array) { $line_consolidate[$i] = join(',', @{$line_data[$i]}) . "\n"; print "$line_consolidate[$i]"; $i ++; } print "----------------------\n"; # 配列をファイルへ出力 open (FH, ">$OUTPUT") or die "$!"; print FH @line_consolidate; close (FH); #// 終了 exit(0);

■実行結果確認
$ ./inoutcsv.pl 要素を配列に格納 ---------------------- 0行0番目の要素: 商品名 0行1番目の要素: 価格 0行2番目の要素: 在庫 1行0番目の要素: ファンタ 1行1番目の要素: 100 1行2番目の要素: 28 2行0番目の要素: キリンレモン 2行1番目の要素: 110 2行2番目の要素: 24 3行0番目の要素: ポカリスエット 3行1番目の要素: 150 3行2番目の要素: 31 4行0番目の要素: 十六茶 4行1番目の要素: 130 4行2番目の要素: 18 5行0番目の要素: アクエリアス 5行1番目の要素: 140 5行2番目の要素: 26 6行0番目の要素: 午後の紅茶 6行1番目の要素: 160 6行2番目の要素: 17 7行0番目の要素: 伊右衛門 7行1番目の要素: 140 7行2番目の要素: 19 ---------------------- 処理対象行: 5 アクエリアスの在庫更新: 25 csvに出力する内容を確認 ---------------------- 商品名,価格,在庫 ファンタ,100,28 キリンレモン,110,24 ポカリスエット,150,31 十六茶,130,18 アクエリアス,140,25 午後の紅茶,160,17 伊右衛門,140,19 ----------------------

■出力されたCSVファイル(goods.csv)を確認
$ cat goods.csv 商品名,価格,在庫 ファンタ,100,28 キリンレモン,110,24 ポカリスエット,150,31 十六茶,130,18 アクエリアス,140,25 午後の紅茶,160,17 伊右衛門,140,19
※アクエリアスの在庫が26→25に更新されCSVファイルに出力された。

2012年12月1日土曜日

AWS(EC2) Amazon Linux 初期環境設定


Amazon Linux 構築後にとりあえずやっておいた方がよさそうな初期環境設定です。
もちろんケースバイケースですが、
rootパスワード設定、OSセキュリティ設定解除、TimeZone変更 etc...
今のところ毎回やっているので個人的防備録的にまとめておきます。

■構成情報
・OS: Amazon Linux AMI release 2012.09(64bit)


■SSHログイン(Putty使う場合のおさらい)
EIP割り当て後、Puttyの 接続 > SSH > 認証 > 認証のためのプライベートKeyファイルに xxxxx.ppk を設定後、接続
Using username "ec2-user". Authenticating with public key "imported-openssh-key" __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___| https://aws.amazon.com/amazon-linux-ami/2012.09-release-notes/ [ec2-user@ip-10-77-30-12 ~]$

■rootパスワード設定
[ec2-user@ip-10-77-30-12 ~]$ sudo passwd Changing password for user root. New password: BAD PASSWORD: it is based on a dictionary word Retype new password: passwd: all authentication tokens updated successfully. [ec2-user@ip-10-77-30-12 ~]$ su - Password: [root@ip-10-77-30-12 ~]#

■AMIバージョン確認
[root@ip-10-77-30-12 ~]# cat /etc/system-release Amazon Linux AMI release 2012.09 [root@ip-10-77-30-12 ~]#

■OSセキュリティ設定解除
[root@ip-10-77-30-12 ~]# chkconfig --list iptables iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off [root@ip-10-77-30-12 ~]# chkconfig --list ip6tables ip6tables 0:off 1:off 2:on 3:on 4:on 5:on 6:off [root@ip-10-77-30-12 ~]# [root@ip-10-77-30-12 ~]# chkconfig iptables off [root@ip-10-77-30-12 ~]# chkconfig ip6tables off [root@ip-10-77-30-12 ~]# [root@ip-10-77-30-12 ~]# chkconfig --list iptables iptables 0:off 1:off 2:off 3:off 4:off 5:off 6:off [root@ip-10-77-30-12 ~]# chkconfig --list ip6tables ip6tables 0:off 1:off 2:off 3:off 4:off 5:off 6:off [root@ip-10-77-30-12 ~]#
※以前は、/etc/sysconfig/selinux の設定をSELINUX=disabledとしていたが、そのファイルが存在しない。

■TimeZone変更
[root@ip-10-77-30-12 ~]# date; cp /usr/share/zoneinfo/Japan /etc/localtime; date Thu Jan 10 15:50:15 UTC 2013 cp: overwrite `/etc/localtime'? y Fri Jan 11 00:50:18 JST 2013 [root@ip-10-77-30-12 ~]#

■root volume増設分を認識させる
EC2作成時、root volumeに20GBを設定したはずだが、デフォルトの8GB分しか認識されていない。下記コマンドで対応する。
[root@ip-10-77-30-12 ~]# df -hT; resize2fs /dev/xvda1; df -hT Filesystem Type Size Used Avail Use% Mounted on /dev/xvda1 ext4 7.9G 836M 7.0G 11% / tmpfs tmpfs 298M 0 298M 0% /dev/shm resize2fs 1.42 (29-Nov-2011) Filesystem at /dev/xvda1 is mounted on /; on-line resizing required old_desc_blocks = 1, new_desc_blocks = 1 Performing an on-line resize of /dev/xvda1 to 4194304 (4k) blocks. The filesystem on /dev/xvda1 is now 4194304 blocks long. Filesystem Type Size Used Avail Use% Mounted on /dev/xvda1 ext4 16G 840M 15G 6% / tmpfs tmpfs 298M 0 298M 0% /dev/shm [root@ip-10-77-30-12 ~]#

■OS再起動
[root@ip-10-77-30-12 ~]# reboot
※VPC上のEC2は再起動してもローカルIPは変わらないし、EIPが外れないので便利。
※このタイミングで一度AMI作成しておくのもありかも。