MySQL道普請便り

第6回mysqlコマンドラインクライアントにページャーを指定する

勉強のためにMySQLをインストールしてデータを投入してみたはいいものの…バンドルされている標準のmysqlコマンドラインクライアントは、使いにくくありませんか? 飾りっ気のないプロンプトにパースが面倒なASCIIの罫線、無いも同然なTabキー補完、間違えて10万行くらいヒットしてしまうと見えなくなる先頭の行…。

今回はそんな悩みを解決するためのmysqlコマンドラインクライアントのTIPSとして、pagerサブコマンドを紹介します。この機能はmysqlコマンドラインクライアントの機能であるため、それ以外のコマンドラインクライアントでは利用できません。また、Windows版のmysqlコマンドラインクライアント(サーバはWindows版のものでも構いません。クライアントです)はページャーに対応していないのでごめんなさい。

デモンストレーション環境について

去る2015/10/21、MySQLの最新版となるMySQL 5.7が製品リリースされました。

が、この回で利用している環境は、第2回 MySQLにはじめてのデータを入れてみるで利用したものを「そのまま」利用しています(つまり、MySQL 5.6のままです⁠⁠。2015/11/02現在、MySQLのyumリポジトリを新しくセットアップしようとした場合、MySQL 5.7がデフォルトで有効となったリポジトリが登録されますmysql-community-release-*.rpmだったファイル名が、mysql57-community-release-*.rpmに変わっています)が、今回紹介するTIPSはMySQL 5.6でもMySQL 5.7でも有効なものを紹介しますので、どちらのバージョンのクライアントでも問題ありません(そして古いMySQL 5.1やMySQL 5.5のクライアントでも問題ありません⁠⁠。

なお、自身の利用しているmysqlコマンドラインクライアントのバージョンを確認するには、--versionオプションを利用します(例として、MySQL 5.7, 5.6, 5.5のコマンドラインクライアントの出力を記載しておきます⁠⁠。


$ /usr/mysql/5.7.9/bin/mysql --version  ### MySQL 5.7のコマンドラインクライアント
/usr/mysql/5.7.9/bin/mysql  Ver 14.14 Distrib 5.7.9, for Linux (x86_64) using  EditLine wrapper

$ /usr/mysql/5.6.27/bin/mysql --version ### MySQL 5.6のコマンドラインクライアント
/usr/mysql/5.6.27/bin/mysql  Ver 14.14 Distrib 5.6.27, for Linux (x86_64) using  EditLine wrapper

$ /usr/mysql/5.5.46/bin/mysql --version ### MySQL 5.5のコマンドラインクライアント
/usr/mysql/5.5.46/bin/mysql  Ver 14.14 Distrib 5.5.46, for Linux (x86_64) using  EditLine wrapper

オプション記法の約束事

本題に入る前に、mysqlコマンド(に限らず、MySQLのプログラム全般…mysqlコマンドやmysqldumpコマンドなどのクライアント、MySQLサーバであるmysqldコマンドも同様です)の解釈するオプションの記法について記載しておきます。

mysqlコマンドの解釈する、⁠値を取るオプション」は原則「ショートオプション 空白文字 値」⁠ショートオプション 値」⁠ロングオプション 空白文字 値」⁠ロングオプション イコール 値」のいずれかの形式で与える必要があります。たとえば、接続ユーザーを指定する-u--userオプションを与える方法は以下の4通りです。

  • mysql -u root ⁠ショートオプション 空白文字 値)
  • mysql -uroot ⁠ショートオプション 値)
  • mysql --user root ⁠ロングオプション 空白文字 値)
  • mysql --user=root ⁠ロングオプション イコール 値)

ただし、パスワード-pまたは--passwordオプションのみ例外となっていて、⁠ショートオプション 値」⁠ロングオプション イコール 値」のいずれかの形式しか取れなくなっています(空白文字を入れて指定する形式が利用できません⁠⁠。

これは、-pオプションは「値を指定された場合はそれをパスワードとして扱う」⁠値が指定されずオプションのみ指定された場合はパスワードプロンプトを表示する」という2通りの動作があるためこのような制約になっています。空白文字を許して値を解釈しようとすると、空白文字の次に来る文字列がパスワードなのか別のオプションなのかの判定がつかないのです(もし-pに空白値のパターンが許されたとすると、mysql -p database1「database1というパスワードを指定し、カレントデータベースは指定しない」⁠パスワードは指定せずパスワードプロンプトを表示し、カレントデータベースはdatabase1とする」と構文上区別がつかなくなります⁠⁠。パスワードの指定時は-p'your_password'もしくは--password='your_password'の形式しか取れないことを憶えておいてください。

pagerオプション

mysqlコマンドにページャーを指定するには、--pagerオプションを指定するか、または、コマンドラインクライアントを起動した状態でpagerサブコマンドを利用します。百聞は一見に如かずと言います。まずは--pagerオプションにlessコマンドを指定して試してみましょう。

$ mysql --pager=less
mysql> SELECT NOW();

おわかりいただけたでしょうか。SELECT NOW()ステートメントの結果がいつも通りターミナルに流れるのではなく、パイプでlessコマンドに渡されたかのように振る舞います。このステートメントでは1行しか結果が返らないので感慨が薄いのですが…そうですね、たとえばこんなステートメントはどうでしょうか。

mysql> SHOW TABLES FROM information_schema;

information_schemaデータベースに含まれるテーブルを一覧するためのSQLですが、これはそこそこ行数があるのでlessコマンドの意味があるのではないでしょうか。さてこの出力結果を見ていると、INNODB_*というテーブルがいくつかあるのが目につきました。lessコマンドにつなぐことができるのであれば、grepコマンドにつなぐことも簡単です。出力結果からINNODB_*にマッチしそうなテーブルだけをページャーを使ってフィルタリングしてみます。

$ mysql --pager="grep 'INNODB_'"
mysql> SHOW TABLES FROM information_schema;

想像した通りに出力されたでしょうか? カラム名の表示やASCIIで引かれた罫線だけの行は出力されませんでした。

図1 ページャーを使ったフィルタリングの結果
図1 ページャーを使ったフィルタリングの結果

これは、カラム名の行や罫線だけの行も含めたmysqlコマンドの出力結果をそのまま全てgrepコマンドに渡したため、"INNODB_"を含まない行であるこれらはgrepコマンドによってフィルタリングされてしまったからです。またその一方で、出力の最後の61 rows in set (x.xx sec)の行は"INNODB_"を含まないにも関わらずフィルタリングされることなく出力されています。これはこの行を出力する部分だけがページャーを通さずに直接sprintfでバッファに書き込まれているためなのですが、どういう思想でこうなっているのかはよくわかりません(興味のある方はこのあたりで実装されているので眺めてみてください⁠⁠。

さて、勘の良い方はすでに気付かれているかも知れませんが、pagerオプションには「パイプを含めた複数のコマンド」を指定することもできます。たとえばさっきのgrepコマンドでフィルタリングをしつつ、その結果をlessコマンドに渡す、というようなオプションの記述は以下のようになります。

$ mysql --pager="grep 'INNODB_' | less"
mysql> SHOW TABLES FROM information_schema;

とても簡単ですね。しかし、ページャーを切り替えるために、都度mysqlコマンドを一度終了してpagerオプションをセットするのは少し面倒です。mysqlコマンドで接続したままページャーを切り替えるためのサブコマンド(ドキュメントなどでは単に「コマンド」とされていますが、mysqlコマンド以外のシェルから起動するコマンドと混同を避けるため、本記事の中ではmysqlコマンド内の「サブコマンド」というスタンスを取って記述しています)pagerサブコマンドです。そのまんまですね。

pagerサブコマンド

mysql> pager wc
mysql> SHOW TABLES FROM information_schema;
     65     189    2730
61 rows in set (0.14 sec)

上記の例は、pagerサブコマンドを利用してページャーをwcコマンドに変更した例です。引数なしのwcコマンドに引き渡したため、罫線と行ヘッダを含め「結果セットが65行であること」⁠転送された中身はおよそ2700バイトであること」が非常にざっくりと確認できます。pagerサブコマンドはpagerオプションと同じように空白やパイプを含んだページャーを指定することができますが、pagerサブコマンドに渡すコマンド全体をクォートしてはいけません

mysql> pager "grep -v INNODB_"
PAGER set to '"grep -v INNODB_"'

mysql> SHOW TABLES FROM information_schema;
sh: grep -v INNODB_: コマンドが見つかりません
61 rows in set (0.21 sec)

クォートしてしまうと、上記のように、クォートされた全体をページャーとして認識してしまうため、⁠コマンドが見つかりません」のエラーになります。pagerサブコマンドに渡すページャーは、シェル上でそのままパイプにつなげるつもりで渡してあげてください。

設定したページャーを元に戻すには、nopagerサブコマンドを実行します。nopagerサブコマンドはpagerサブコマンドで指定したページャーのみならず、pagerオプションで指定した値も無効化して標準出力に戻します。

mysql> nopager
PAGER set to stdout

便利なページャー

さて、ページャーの指定の仕方は一通り説明できたと思いますので、実際に筆者がよく使うページャーを紹介したいと思います。

less

何はなくともlessコマンドです。出力結果が長くなる時、キーボードだけでスクロールできるのはとにかく便利です。たとえば、シリアルコンソールでログインして作業をする場合(つまり、ターミナルのスクロールができない場合)などはこれが無いと泣きたくなってしまいます。lessですので出力内容を検索することもできます。

なお、mysqlコマンドラインクライアントはMySQLサーバからの転送を全てバッファリングしてからページャーを起動するため、巨大な結果セットに対して「末尾を参照する」lessコマンド内で"G")などの操作をしても、そのタイミングでは通信は発生しません(すでに送信済みのものをクライアント側で操作します⁠⁠。つまり、先頭の1ページだけ見てlessコマンドを終了してしまう場合でも、結果セットの全てが転送されます。この動作を変更して、lessのページング動作に合わせて通信を発生させたい場合は、mysqlコマンドラインクライアントに-q--quickオプションを指定します。

grep -v Sleep

SHOW PROCESSLISTを見る時によく使います。スリープしているスレッドを除外した、今動いているスレッドのみを一覧することができ、とても便利です。派生としてegrep -v Sleep|Binlog|handlersocketなどもあります(レプリケーションスレーブのステータスであるBinlog DumpBinlog GTID DumpHandlerSocketプラグインのスレッドも除外)

cat > /dev/null

結果セットを全て/dev/nullにリダイレクトし、何も表示させません。主に、結果セットが大きく画面に表示したくない、かつ、レスポンスタイムのみ確認したい場合や、キャッシュに載せるためだけに実行する場合に利用します。ただし、lessの時と同じく何も表示されないとはいえ、MySQLサーバはmysqlコマンドラインクライアントに対して結果セットを送信しきっており、mysqlコマンドラインクライアント側で破棄されるだけであることに注意してください。

wc

結果セットのサイズをとてもざっくりと計るために使います(行ヘッダや罫線が含まれている分の誤差や結果セット以外のプロトコルのやり取りなどがありますので、正確な転送量ではありません⁠⁠。正確ではないとはいえ、この値で40MBもの値が返ってきたらそれは結果セットのサイズが大きすぎるんじゃないか…という推測の時に使ったりします。

tee

teeコマンドを通せばオペログが取れるんじゃないか! という思いもありますが、残念、ページャーが通るのはクエリの結果だけなので、肝心の実行したクエリーを記録することができません。そもそもそういう用途にteeオプションやteeサブコマンドがあります。

他にもvim -R -gzip -c > /tmp/result.gzssh ipaddr "cat - > ~/result.txt"loggerなど、いろいろな楽しみ方があると思います。ぜひ、お気に入りのページャーを見つけてください。

おすすめ記事

記事・ニュース一覧