オライリー矢野様より、いつもどおり献本御礼。

そういえば、これがなかった。

ある意味、(Perl|Python|Ruby)クックブックより重要とも言える、これが。

本書「bashクックブック」は、世界でも最も普及したshell、Bashのクックブックであると同時に、2008年現在における「デフォルトのコマンドライン環境」において、「あれをやるにはどうしたらよいか」、すなわち「CLIクックブック」としても機能するよう書かれた一冊。

本書の何がよいかといえば、何もかもBashでやろうとしていないこと。目次(長いので最後に掲載)を見ればわかるとおり例えばfindの使いかなどは、Bashユーザーでなくとも役に立つ。そして、それがより簡潔ならperlを使うことも厭わない。要するに、普通にCLI(Command-Line Interface)で何かしようとするときに、一番普通にやる方法を紹介しているのが本書だということだ。

「普通の人はCLIなんか使わない」といったら大間違い。むしろかつてよりも普通の人がCLIを使う機会は、OS XとUbuntuをはじめとするDesktop Linuxの普及でむしろ増えているとさえ言える。どちらも優れたGUIを持ち、GUIでほとんど全てのことが出来るようにはなっているが、しかし何百個のファイルを移動したり改名したりするのはGUIではきつすぎる。shellからならちょちょいのちょいである。

CLIにはもう一つ、「書いてある通りにやれ」が通用するという素晴らしい美点もある。「アプリケーションフォルダーのほにゃららのあにゃららを開いて、こにゃららメニューからふにゃららを選択し....」と言わずとも、「Terminalを開いたら、あとはこれをコピペしろ」が効くのだ。端末ソフトのおかげで、GUIとCLIの組み合わせはどちらか片方よりもずっと強力で洗練された環境を得られるのだ。

遠隔操作のやりやすさも見逃せない。今やデータセンターにおいてあるサーバーを手元のパソコンから操作するというのはギークの専売特許ではない。確かにblogを書くだけならブラウザーからでも出来るが、blog環境を自分で構築して管理するというのであれば、どうしたってsshの世話になることになる。もちろんリモートデスクトップというものは確かにあって、あれはあれで快適なものなのだけど、kill -HUP PID一発で事足りる作業で使うのは牛刀でひげ剃りもいいところだ。

そんな時常に世話になるのが、shellというプログラムで、そして複数あるshellの中でも最も普及しているのがbashだというのは疑いようがない。なにしろOS XとLinuxでデフォルトである。Linux Distributionの一部に至っては/bin/shを兼ねている場合すらある。

一言で言えば、電脳と対話する際に、相手として最も多いのがbashで、本書はそのクックブックというわけなのだ。今までのクックブックの中では、最も潜在読者が多いクックブックなのではないだろうか。プログラマーでなくても使う機会があるという意味では特にそうである。ネットワーク管理者は必携だろう。

もっとも私は、20年以上tcshユーザー。私がUnixユーザーとなった頃にはshはあってもbashはなかったのだ。しかし、tcshに限らずcshではshell scriptを書きづらいという問題がある。特にFile Descriptorを数値で明示指定できないというのは時には致命的で、cshでshell scriptはbad practiceの代表とされている。本書は shell script の書き方指南としても実によい。

もっとも、私がshell scriptを新たに書き下ろすことは滅多にない。Perlで全部書いた方が簡潔だしポータブルだから。それでも、shell scriptとつきあわない訳には行かない。書き下ろしではなく書き直しという需要があるからだ。/etcの下を覗きたかったら、shell、それも/bin/shの知識が必須になる。本書は「shクックブック」としても使えるように書かれていて、今までshell scriptの構文を忘れては(ex. 「あれ? if を閉じるのっって fi だったっけ endif だったっけ?」) FreeBSD の /etcの下をカンニング帳がわりに覗いていた私には実にうれしい一冊だ。

映画「ジュラシックパーク」で、「Unixなら私も使えるわ」がお笑いネタになったのは、UnixなのにshellがGUIどころか3Dだったから。ほんとうの「はかー」は、ほとんどの場合 shell に呪文を唱えるのです。そして shell は別に「はかー」や「ぎーく」のためのものではありません。利用者、ユーザーのために存在するのです。

そんなわけで、本書はオライリー動物シリーズの中で、最も一般向けの一冊かも。厚さと値段までそうでないのが残念なところだけど。

Dan the Shell User for Two Decades

追記: Ubuntu の bash の調教のいきとどきぶりにちょっとびっくり。この俺がchshもせずドットファイルも修正せずにそのまあ使っているなんて!

目次 - oreilly.co.jp -- Online Catalog: bashクックブックより
目次
はじめに
1章 bash の概要
レシピ1.1 プロンプトの解読
レシピ1.2 カレントディレクトリの表示
レシピ1.3 コマンドの検索と実行
レシピ1.4 ファイルに関する情報の取得
レシピ1.5 カレントディレクトリ内のすべての隠しファイルの表示
レシピ1.6 シェルの引用符の使用
レシピ1.7 組み込みコマンドと外部コマンドの使用または置換
レシピ1.8 対話形式で実行しているかどうかの判断
レシピ1.9 デフォルトシェルとしてのbash の設定
レシピ1.10 Linux 用のbash の入手
レシピ1.11 xBSD 用のbash の入手
レシピ1.12 Mac OS X 用のbash の入手
レシピ1.13 Unix 用のbash の入手
レシピ1.14 Windows 用のbash の入手
レシピ1.15 bash を入手せずにbash を体験する
レシピ1.16 bash の参考資料
2章 標準出力
レシピ2.1 ターミナルウィンドウへの出力の書き出し
レシピ2.2 スペースを維持した出力の生成
レシピ2.3 出力の書式制御
レシピ2.4 改行なしの出力
レシピ2.5 コマンド出力の保存
レシピ2.6 他のファイルへの出力の保存
レシピ2.7 ls コマンドの出力の保存
レシピ2.8 出力とエラーメッセージの個別ファイルへのリダイレクト
レシピ2.9 出力とエラーメッセージの同じファイルへのリダイレクト
レシピ2.10 出力の付加
レシピ2.11 ファイルの先頭または末尾だけの使用
レシピ2.12 ファイル内のヘッダーのスキップ
レシピ2.13 出力の削除
レシピ2.14 複数のコマンドからの出力の保存またはグループ化
レシピ2.15 出力を入力として使用した2 つのプログラムの連結
レシピ2.16 出力を入力として使用するときのコピー
レシピ2.17 出力を引数として使用する2 つのプログラムの連結
レシピ2.18 1 行での複数のリダイレクトの使用
レシピ2.19 リダイレクトがうまくいかない場合の出力の保存
レシピ2.20 STDERR とSTDOUT の交換
レシピ2.21 不慮によるファイルの上書きの防止
レシピ2.22 ファイルの意図的な上書き
3章 標準入力
レシピ3.1 ファイルからの入力の取得
レシピ3.2 スクリプトでのデータの維持
レシピ3.3 ヒアドキュメントでの奇妙な振る舞いの防止
レシピ3.4 ヒアドキュメントのインデント
レシピ3.5 ユーザー入力の取得
レシピ3.6 Yes/No 入力の取得
レシピ3.7 オプションリストからの選択
レシピ3.8 パスワード入力の要求
4章 コマンドの実行
レシピ4.1 実行可能プログラムの実行
レシピ4.2 コマンドの成功または失敗の通知
レシピ4.3 複数のコマンドの連続実行
レシピ4.4 複数のコマンドの同時実行
レシピ4.5 コマンドが成功したかどうかの判断
レシピ4.6 if 文の控えめな使用
レシピ4.7 時間のかかるジョブの無人実行
レシピ4.8 失敗時のエラーメッセージの表示
レシピ4.9 変数からのコマンドの実行
レシピ4.10 ディレクトリ内のすべてのスクリプトの実行
5章 基本的なスクリプティング:シェル変数
レシピ5.1 スクリプトのドキュメント化
レシピ5.2 シェルスクリプトへのドキュメントの埋め込み
レシピ5.3 スクリプトの読みやすさの改善
レシピ5.4 変数名と周囲のテキストとの分離
レシピ5.5 変数のエクスポート
レシピ5.6 すべての変数値の参照
レシピ5.7 シェルスクリプトでのパラメータの使用
レシピ5.8 スクリプトに渡す引数の反復処理
レシピ5.9 スペースが含まれたパラメータの処理
レシピ5.10 スペースが含まれたパラメータリストの処理
レシピ5.11 引数のカウント
レシピ5.12 引数の使用
レシピ5.13 デフォルト値の取得
レシピ5.14 デフォルト値の設定
レシピ5.15 有効なデフォルト値としてのnull の使用
レシピ5.16 定数文字列以外のデフォルトの使用
レシピ5.17 未設定のパラメータに対するエラーメッセージの表示
レシピ5.18 文字列の部分的な変更
レシピ5.19 配列変数の使用
6章 シェルのロジックと算術演算
レシピ6.1 シェルスクリプトでの算術演算の実行
レシピ6.2 条件分岐
レシピ6.3 ファイル属性の評価
レシピ6.4 複数の属性の評価
レシピ6.5 文字列属性の評価
レシピ6.6 等価の評価
レシピ6.7 パターンマッチングによる評価
レシピ6.8 正規表現による評価
レシピ6.9 リダイレクトによる振る舞いの変更
レシピ6.10 while ループ
レシピ6.11 read によるループ
レシピ6.12 カウントによるループ
レシピ6.13 浮動小数点数値によるループ
レシピ6.14 多分岐
レシピ6.15 コマンドライン引数の解析
レシピ6.16 単純なメニューの作成
レシピ6.17 単純なメニューでのプロンプトの変更
レシピ6.18 単純なRPN 計算機の作成
レシピ6.19 コマンドライン計算機の作成
7章 シェルのユーティリティI
レシピ7.1 ファイルでの文字列の検索
レシピ7.2 検索結果からのファイル名の取得
レシピ7.3 検索結果からの真偽値の取得
レシピ7.4 大文字と小文字を区別しないテキストの検索
レシピ7.5 パイプラインでの検索
レシピ7.6 検索結果の絞り込み
レシピ7.7 複雑なパターンの検索
レシピ7.8 社会保障番号の検索
レシピ7.9 圧縮ファイルのgrep
レシピ7.10 出力の絞り込み
レシピ7.11 出力行の絞り込み
レシピ7.12 各行での単語の反転
レシピ7.13 数値のリストの合計
レシピ7.14 文字列値のカウント
レシピ7.15 ヒストグラムによるデータの表示
レシピ7.16 検出したフレーズの後の段落の表示
8章 シェルのユーティリティII
レシピ8.1 出力のソート
レシピ8.2 数値のソート
レシピ8.3 IP アドレスのソート
レシピ8.4 出力の部分的な切り取り
レシピ8.5 重複行の削除
レシピ8.6 ファイルの圧縮
レシピ8.7 ファイルの圧縮解除
レシピ8.8 tar アーカイブでの一意なディレクトリの確認
レシピ8.9 文字の変換
レシピ8.10 大文字から小文字への変換
レシピ8.11 DOS ファイルからLinux フォーマットへの変換
レシピ8.12 スマート引用符の削除
レシピ8.13 ファイル内の行、単語、文字のカウント
レシピ8.14 段落の折り返し
レシピ8.15 less の活用
9章 ファイルの検索
レシピ9.1 すべてのMP3 ファイルの検索
レシピ9.2 特殊文字が含まれたファイル名の処理
レシピ9.3 検索したファイルでの処理の高速化
レシピ9.4 シンボリックリンクに対応したファイルの検索
レシピ9.5 大文字と小文字を区別しないファイルの検索
レシピ9.6 日付によるファイルの検索
レシピ9.7 ファイルの種類によるファイルの検索
レシピ9.8 サイズによるファイルの検索
レシピ9.9 内容によるファイルの検索
レシピ9.10 既存のファイルおよび内容の高速な検索
レシピ9.11 場所の候補リストに基づくファイルの検索
10章 スクリプティングのための追加機能
レシピ10.1 スクリプトのデーモン化
レシピ10.2 include とsource によるコードの再利用
レシピ10.3 スクリプトでのコンフィグレーションファイルの使用
レシピ10.4 関数の定義
レシピ10.5 関数の使用:パラメータと戻り値
レシピ10.6 割り込みの捕捉
レシピ10.7 エイリアスによるコマンドの再定義
レシピ10.8 エイリアスと関数の無効化
11章 日付と時刻の操作
レシピ11.1 日付を表示するための書式設定
レシピ11.2 デフォルトの日付の提供
レシピ11.3 日付の範囲の自動設定
レシピ11.4 日時からエポック秒への変換
レシピ11.5 エポック秒から日時への変換
レシピ11.6 Perl による昨日または明日の日付の取得
レシピ11.7 日時の算術演算
レシピ11.8 タイムゾーン、夏時間、うるう年の処理
レシピ11.9 スクリプトのスケジューリング
12章 シェルスクリプトとしてのエンドユーザータスク
レシピ12.1 ダッシュの表示
レシピ12.2 アルバムの写真の表示
レシピ12.3 MP3 プレイヤーのロード
レシピ12.4 CD の作成
レシピ12.5 2 つのドキュメントの比較
13章 解析
レシピ13.1 シェルスクリプトの引数の解析
レシピ13.2 エラーメッセージによる引数の解析
レシピ13.3 HTML の解析
レシピ13.4 出力から配列への解析
レシピ13.5 関数呼び出しによる出力の解析
レシピ13.6 read 文によるテキストの解析
レシピ13.7 read 文による配列への解析
レシピ13.8 複数形の正しい処理
レシピ13.9 1 文字ずつの取得
レシピ13.10 SVN ソースツリーの整理
レシピ13.11 MySQL によるデータベースのセットアップ
レシピ13.12 データからのフィールドの分離
レシピ13.13 データファイルでの特定のフィールドの更新
レシピ13.14 ホワイトスペースの削除
レシピ13.15 ホワイトスペースの圧縮
レシピ13.16 固定長のレコードの処理
レシピ13.17 改行のないファイルの処理
レシピ13.18 データファイルからCSV への変換
レシピ13.19 CSV データファイルの解析
14章 安全なシェルスクリプトの記述
レシピ14.1 一般的なセキュリティ問題の回避
レシピ14.2 インタープリタスプーフィングの回避
レシピ14.3 安全な$PATH の設定
レシピ14.4 すべてのエイリアスの解除
レシピ14.5 コマンドハッシュの削除
レシピ14.6 コアダンプの回避
レシピ14.7 安全な$IFS の設定
レシピ14.8 安全なumask の設定
レシピ14.9 $PATH での外部からの書き込みが可能なディレクトリの検索
レシピ14.10 $PATH へのカレントディレクトリの追加
レシピ14.11 安全な一時ファイルの使用
レシピ14.12 入力の検証
レシピ14.13 パーミッションの設定
レシピ14.14 プロセスリストへのパスワードの漏えい
レシピ14.15 setuid またはsetgid スクリプトの記述
レシピ14.16 Guest ユーザーの制限
レシピ14.17 chroot jail の使用
レシピ14.18 非root ユーザーとしての実行
レシピ14.19 sudo のより安全な使用
レシピ14.20 スクリプトでのパスワードの使用
レシピ14.21 パスワードなしでのSSH の使用
レシピ14.22 SSH コマンドの制限
レシピ14.23 非アクティブセッションの切断
15章 高度なスクリプティング
レシピ15.1 #!に対する可搬性の確認
レシピ15.2 POSIX $PATH の設定
レシピ15.3 可搬性のあるシェルスクリプトの開発
レシピ15.4 VMware でのスクリプトのテスト
レシピ15.5 可搬性のあるfor ループの使用
レシピ15.6 可搬性のあるecho の使用
レシピ15.7 必要に応じた出力の分割
レシピ15.8 16 進数での出力の表示
レシピ15.9 bash ネットワークリダイレクトの使用
レシピ15.10 IP アドレスの検索
レシピ15.11 別のマシンからの入力の取得
レシピ15.12 スクリプト全体の出力のリダイレクト
レシピ15.13 「引数リストが長すぎる」エラーへの対処
レシピ15.14 スクリプトからsyslog へのログの記録
レシピ15.15 スクリプトからの電子メールの送信
レシピ15.16 段階的なプロセスの自動化
16章 bash のコンフィグレーションとカスタマイズ
レシピ16.1 bash のスタートアップオプション
レシピ16.2 プロンプトのカスタマイズ
レシピ16.3 $PATH の永続的な変更
レシピ16.4 $PATH の一時的な変更
レシピ16.5 $CDPATH の設定
レシピ16.6 コマンド名の短縮または変更
レシピ16.7 シェルの振る舞いと環境の調整
レシピ16.8 .inputrc によるreadline の振る舞いの調整
レシピ16.9 ./bin の追加によるプライベートユーティリティの管理
レシピ16.10 二次プロンプトの使用: $PS2、$PS3、$PS4
レシピ16.11 セッション間でのシェル履歴の同期
レシピ16.12 シェル履歴オプションの設定
レシピ16.13 便利なcd コマンドの作成
レシピ16.14 ディレクトリの新規作成とそのディレクトリへの移動の同時実行
レシピ16.15 最後のディレクトリへの移動
レシピ16.16 ロード可能な組み込みコマンドによるbash への新機能の追加
レシピ16.17 プログラム可能な補完機能の改良
レシピ16.18 初期化ファイルの正しい使用
レシピ16.19 可搬性のある自己完結型のRC ファイルの作成
レシピ16.20 カスタムコンフィグレーションの開始
17章 管理タスク
レシピ17.1 多数のファイル名の変更
レシピ17.2 Linux でのGNU Texinfo およびInfo の使用
レシピ17.3 複数のZIP ファイルの圧縮解除
レシピ17.4 screen による切断されたセッションの回復
レシピ17.5 単一のbash セッションの共有
レシピ17.6 セッション全体またはバッチジョブのログ
レシピ17.7 ログアウト時の画面の消去
レシピ17.8 修復のためのファイルメタデータの取得
レシピ17.9 多くのファイルでのインデックスの作成
レシピ17.10 diff とpatch の使用
レシピ17.11 ファイル間の相違点のカウント
レシピ17.12 名前に特殊な文字が含まれたファイルの削除または名前の変更
レシピ17.13 ファイルの先頭へのデータの追加
レシピ17.14 ファイルのインプレース編集
レシピ17.15 コマンドグループでのsudo の使用
レシピ17.16 一方のファイルにのみ存在する行の検出
レシピ17.17 最新のN 個のオブジェクトの維持
レシピ17.18 grep プロセス自体を除いたps 出力のgrep
レシピ17.19 プロセスが実行されているかどうかの確認
レシピ17.20 出力へのプレフィックスまたはサフィックスの追加
レシピ17.21 行番号の追加
レシピ17.22 数列の書き出し
レシピ17.23 DOS のpause コマンドのエミュレート
レシピ17.24 数字の桁区切り
18章 入力作業の軽減による作業時間の短縮
レシピ18.1 ディレクトリ間でのすばやい移動
レシピ18.2 最後のコマンドの繰り返し
レシピ18.3 ほぼ同じコマンドの実行
レシピ18.4 単語の境界を越えた置換
レシピ18.5 引数の再利用
レシピ18.6 名前の補完
レシピ18.7 安全な入力
19章 ヒントと対策
レシピ19.1 実行パーミッションの設定
レシピ19.2 「そのようなファイルやディレクトリはありません」エラーの修正
レシピ19.3 $PATH とよく使用するスクリプトの実行
レシピ19.4 テストスクリプトの命名
レシピ19.5 エクスポートされた変数の変更
レシピ19.6 代入時の引用符の使用
レシピ19.7 パターンマッチングによるアルファベット順の並べ替え
レシピ19.8 パイプラインによるサブシェルの作成
レシピ19.9 ターミナルの回復
レシピ19.10 空の変数によるファイルの削除
レシピ19.11 printf の奇妙な振る舞い
レシピ19.12 bash スクリプトの構文のテスト
レシピ19.13 スクリプトのデバッグ
レシピ19.14 関数を使用するときのエラーの回避
レシピ19.15 シェルのワイルドカードと正規表現の区別
付録A リファレンス
A.1 bash の実行
A.2 プロンプト文のカスタマイズ
A.3 ANSI カラーエスケープシーケンス
A.4 組み込みコマンドと予約語
A.5 環境変数
A.6 set オプション
A.7 shopt オプション
A.8 set、shopt、環境変数によるシェルの振る舞いの調整
A.9 test 演算子
A.10 I/O リダイレクト
A.11 echo オプションとエスケープシーケンス
A.12 printf
A.13 strftime による日時文字列の書式設定
A.14 パターンマッチング文字
A.15 extglob の拡張パターンマッチング演算子
A.16 tr エスケープシーケンス
A.17 Readline の初期化ファイルの構文
A.18 Emacs モードのコマンド
A.19 vi モードのコマンド
A.20 ASCII 値の表
付録B bash に含まれているサンプル
B.1 startup-files ディレクトリの例
付録C コマンドラインの処理
C.1 コマンドラインを処理する手順
付録D リビジョン管理
D.1 CVS
D.2 Subversion
D.3 RCS
D.4 その他
付録E ソースからのbash のビルド
E.1 bash の入手
E.2 アーカイブの展開
E.3 アーカイブの内容
E.4 問い合わせ先
索引