2011年1月19日

如何在 Shell Script 中捉取 MySQL 資料庫中的指定記錄值

很久沒寫 Blog 了,也許是因為撞牆期吧?
總之,來寫個跟 Shell Script 及 MySQL 有關的東西吧:如何在 Shell Script 中直接取得 MySQL 資料庫中某記錄的值!

需求起因

事情的發展是這樣的:為了確保系統發出的 EMAIL 能有效的送達用戶手上,所以懶人如格揆我就很順手的把 /var/log/maillog 中的郵件寄送記錄給解出來了,反正不需要我每天動手做的任何方式都是最佳的方式。但是,代誌毋係憨人想ㄟ哈呢甘單,沒多久就有人寄信來希望能加上信件主旨,於是格揆很快的又回到每日人工查資料的機械生活中,這完全是忤逆懶人天性,違乎常理的發展啊。
就因為『懶散要超越懶散』,格揆我其實一直希望能把這動作併入 Shell 中自動補完,終於在今天找出了正確的解法,先記錄一下以免腦殘之後忘了該怎麼辦!

編碼問題

在讀取資料庫中的資訊前有一點很重要:系統編碼!
mysql> status
--------------
mysql  Ver 14.12 Distrib 5.0.77, for redhat-linux-gnu (i686) using readline 5.1

Connection id:          2468601
Current database:       *** 不要問 ***
Current user:           *** 很恐怖 ***
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.0.86-community-log MySQL Community Edition (GPL)
Protocol version:       10
Connection:             *** 您知道的 ***
Server characterset:    latin1
Db     characterset:    utf8
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:               3306
Uptime:                 428 days 21 hours 44 min 57 sec

Threads: 8  Questions: 115577998  Slow queries: 8  Opens: 81015  Flush tables: 1  Open tables: 64  Queries per second avg: 3.119
--------------
如果登入 MySQL 時看到了像是上圖中顯示了不同的編碼狀態,那麼任何 select 到的中文字都會變成亂碼!這問題不難處理,在使用 MySQL Command line Tools 加上 --default-character-set=encodename 即可,如上例即應改由以下方式登入 MySQL:
[ada@myhost ~]$ mysql --default-character-set=utf8
加上了預設編碼設定後後,再到 mysql 命令列工具中下達 status 指令就會看到編碼設定已經被改過了,如下:
Server characterset:    latin1
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8

Select 取值方式

之前在對 Oracle 進行操作時,它有提供如何在 Shell 中去讀取資料庫內容的作法,這裡用讀取資料庫系統時間作為例子:
[ada@ora ~]$ NOW=$(sqlplus -s << END
> set heading off
> set feedback off
> select sysdate from dual;
> exit;
> END)
[ada@ora ~]$ echo $NOW
2011-01-19 17:02:48
但如果想要在 MySQL 中如法泡製的話,輸出結果顯然需要額外再加工才行,如下所示:
[ada@myhost MYSQL]$ NOW=$(mysql --default-character-set=utf8 --silent -E <<END
select now();
END)
[ada@myhost MYSQL]# echo $NOW
*************************** 1. row *************************** now(): 2011-01-19 16:40:25
靠杯,為什麼兩台的時間差這麼多?
還好 MySQL 另外提供一個方式可以讓我們只看到實際輸出資料而沒有欄位名稱什麼的,如下例:
[ada@myhost MYSQL]$ NOW=$(echo "select now()" | mysql --default-character-set=utf8 --silent)
[ada@myhost MYSQL]# echo $NOW
2011-01-19 17:07:56
好啦,想要在 Shell 中去讀取 MySQL 中的某個值就是這麼簡單。如果要撈的是多筆、多欄位的資料呢?沒有問題,系統會用空白串接所有擷取出的欄位值,這樣會比較難處理,但它確確實實還是能夠加以操作。
[ada@myhost MYSQL]# LIST=$(echo "select status, time_start, creator from epaper" | mysql --silent)
[ada@myhost MYSQL]$ echo $LIST
0 2012-08-03 00:00:00 admin 1 2010-09-01 00:00:00 admin 0 2011-09-08 00:00:00 admin 0 2011-09-03 00:00:00 admin 1 2010-10-02 00:00:00 admin 1 2010-10-05 00:00:00 admin 1 2010-10-05 00:00:00 admin 1 2010-10-05 00:00:00 admin 0 2011-11-11 00:00:00 admin 1 2010-11-03 00:00:00 admin 0 2011-11-05 00:00:00 admin 0 2011-11-07 00:00:00 admin 1 2010-11-05 00:00:00 admin 1 2010-12-01 00:00:00 admin 1 2010-12-02 00:00:00 admin 0 2012-12-06 00:00:00 admin 1 2011-01-15 00:00:00 admin
其實也可以改成以下這樣啦,只不過這樣會多出欄位標題出來,需要自行濾除...
[ada@myhost MYSQL]$ mysql --default-character-set=utf8 --silent -e 'select status, time_start, creator from epaper'
status  time_start      creator
0       2012-08-03 00:00:00     admin
1       2010-09-01 00:00:00     admin
0       2011-09-08 00:00:00     admin
0       2011-09-03 00:00:00     admin
1       2010-10-02 00:00:00     admin
1       2010-10-05 00:00:00     admin
1       2010-10-05 00:00:00     admin
1       2010-10-05 00:00:00     admin
0       2011-11-11 00:00:00     admin
1       2010-11-03 00:00:00     admin
0       2011-11-05 00:00:00     admin
0       2011-11-07 00:00:00     admin
1       2010-11-05 00:00:00     admin
1       2010-12-01 00:00:00     admin
1       2010-12-02 00:00:00     admin
0       2012-12-06 00:00:00     admin
1       2011-01-15 00:00:00     admin

[ada@myhost MYSQL]$