zshが無いと死ぬ人がbashでなんとかする
※この記事は、zsh Advent Calendar 2014 - Qiitaの19日目です。
zsh無しにbashで生きる
zsh大好きな皆さんは、bashを心の中のどこかでバカにしているのではないでしょうか。しかし最近のbashは、いろいろとzshを意識している(?)雰囲気があり、zsh特有だと思っていた機能が実はbashでも使えたりします。
そのため、
- zshを使えないと全身から血を吹き出して死ぬ
- ログインシェルとしてzshが起動されないと発狂して死ぬ
- 「最近はSolarisにだってzshが入っている」と一日100回は唱えないと死ぬ
- zsh神社が欲しい、参拝したい
という人でも、bashがあれば多少の延命ができるかもしれません。本稿では、zshが無いというサバイバル環境下において、bashでなんとかすることをテーマにいくつかサンプルを挙げてみます。
なおここでは、bashのプロンプトを$、zshのプロンプトを%として表記します。zshの%は、「宇宙」を意味しています。zshは宇宙だからです。
bashの補完を強力にする - Programmable Completion
zshでpingを打つときには、ホスト名を/etc/hostsに書いておけばTabキーで補完できます。
% ping ma[Tabキー] % ping macmini <嬉しい!>
一方bashでは、先頭に@が付いている場合のみTabキーによるホスト名の補完が効きます。そのためsshの時は良いのですが、pingでは補完されません。
先頭に@があれば、ホスト名として/etc/hostsから補完される: $ ssh ozuma@ma[Tabキー] $ ssh ozuma@macmini <嬉しい!> しかしpingの宛先は@が付かないので、補完されない: $ ping ma[Tabキー] $ ping ma <Shit!>
「だからbashはダメだ」と鍛えられたzsh使いは思うことでしょう。しかし、実はbashでも、プログラム補完(Programmable Completion)という機能でzshと同様に補完できるのです。
プログラム補完を有効にする
プログラム補完は、機能自体はbashに組み込まれていますが、設定ファイルを別途用意する必要があります。
CentOS 6では、これら設定ファイルはbash-completionというパッケージに用意されています。ただしこのbash-completionパッケージはCentOS公式リポジトリには無く、EPELにしか用意されていません。そのため必要な場合にはEPELリポジトリから別途インストールする必要があります。
一方、CentOS 7ならば、公式のbaseリポジトリに用意されています。
$ yum info bash-completion ....省略.... 利用可能なパッケージ 名前 : bash-completion アーキテクチャー : noarch エポック : 1 バージョン : 2.1 リリース : 6.el7 容量 : 85 k リポジトリー : base/7/x86_64 要約 : Programmable completion for Bash URL : http://bash-completion.alioth.debian.org/ ライセンス : GPLv2+ 説明 : bash-completion is a collection of shell functions that take advantage : of the programmable completion feature of bash.
CentOS 6/7のどちらにしろ、bash-completeパッケージをyumコマンドでインストールするだけで準備完了です。
# yum install bash-complete
現在の補完設定を確認する
bashのビルトインコマンドであるcompleteを引数無しで実行すると、現在設定されている補完リストが表示されます。
$ complete complete -F _kill kill complete -F _renice renice complete -o default -F _service tomcat complete -F _smbpasswd smbpasswd complete -F _pgrep pidof complete -F _postconf postconf complete -F _update_alternatives alternatives ......
例えば、pingコマンドに対しては以下のように定義されています。
complete -F _known_hosts ping
プログラム補完は、ping以外にも様々なコマンドに対応しています。例えばsysctlのクソ長い記述も、Tabで補完できます。TCPによるSYN Flood攻撃の際に重要となる、net.ipv4.tcp_synack_retriesを補完してみましょう。
$ sysctl net.ipv4.tcp_syna[Tabキー] $ sysctl net.ipv4.tcp_synack_retries <嬉しい!> net.ipv4.tcp_synack_retries = 5
またopensslコマンドのような、増築に増築を重ね続けてそびえ立つクソ複雑なコマンドも、うろ覚えで利用できます。
$ openssl x[Tabキー] $ openssl x509 -[Tabキー][Tabキー] -C -clrtrust -issuer -req -CA -dates -issuer_hash -serial -CAcreateserial -days -keyform -set_serial -CAform -email -md2 -setalias .........
他にも、そんなもん誰が使うんだって感じですが、iptablesのチェイン名なども補完できます。
# iptables -A I[Tabキー] # iptables -A INPUT <別に嬉しくない!>
興味のある方は、/etc/bash_completion.dの中を覗いてみましょう。プログラム補完の設定自体はシェルスクリプトで書かれているので、なんとなくオーラで分かると思います。
パス名展開で「**」を使えるようにする - globstar
zshでよく使われるのが、**というパス名展開です。あるディレクトリ配下のファイルを根こそぎ相手にしたいときに役に立ちます。
% wc -l **/*.java
これはbashでも、shoptコマンドでglobstarというオプションを設定してやることで利用できます。
$ shopt -s globstar $ wc -l **/*.java
これで、「書いたJavaソースファイルの行数(だけ)で進捗を測る」というクソ環境でも安心です。コメント行とimport文をモリモリ増やしましょう。
cdコマンドを省略する - autocd
zshユーザは忙しいので(もちろん~/.zshrcのカスタマイズに忙しいのです)、「cd」の2文字すら打つのを嫌がります。そのため、cdコマンドを省略できるauto_cdを設定している人が多くいます。
% setopt auto_cd % pwd / % bin % pwd /bin
これは、忙しいbashユーザ(もちろん~/.bashrcのカスタマイズに忙しいのです)も利用できます。zshと同様に、autocdというオプションをshoptコマンドで設定できます。
$ pwd / $ shopt -s autocd $ bin cd bin $ pwd /bin
大文字小文字を無視して補完する
zshユーザは余計な暗記をしたくないので(zshの機能を覚えたいので)、ファイル名の記憶が常におぼろげで曖昧です。そのため、大文字小文字を無視して補完してくれる以下のような設定を、~/.zshrcに書いておくことが好まれます。これで大文字小文字を無視して、Tabキーで補完できます。
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
一方bashでは、事情がちょっぴり複雑です。現在のbashには、zshと同様に大文字小文字を無視して補完させる明示的なオプションはありません。ただし、~/.inputrcに以下のように書いておくことで、bashでも大文字小文字を無視してTabキーで補完することができます。
set completion-ignore-case on
しかし、~/.inputrcはreadlineの設定ファイルであり、bashのみから使われるわけではないので、若干気持ち悪いです。副作用に気をつけましょう。
追記:~/.inputrc のカスタマイズをbashにのみ効かせる
コメントで id:xxmagai さんから教えてもらいましたが、次のように~/.inputrcファイル内でif文を使うことで、設定をbashのみに限定できます。
$if Bash set completion-ignore-case on $endif
詳しくはinfo readlineして、「1.3.2 Conditional Init Constructs」辺りを読みましょう。
前述のように、~/.inputrc にそのまま書くとreadlineを使うコマンド全てに影響があるので、例えばftpでも大文字小文字補完が効くようになります。だからと言って困ることはあまりないでしょうが、やはりif文を使ってbash限定にしておいた方が好ましいでしょう。
nocaseglobはちょっと違う
bashのnocaseglobというオプションをshoptコマンドで設定すると、大文字小文字を無視してパス名展開されるようになります。ただしこれは、Tabキー補完はできません。この点、時々勘違いして書かれている文書があるので注意が必要です。
$ shopt -s nocaseglob $ ls RUNNING.txt $ less run[Tabキー] <補完されない!> $ ls running.* RUNNING.txt <大文字小文字無視してパス名展開された!>
このようにnocaseglobは、あくまでパス名展開のみの機能です。
最後に宣伝
6月にシェルスクリプトの本を出しましたが、このたびKindle版も出ました。興味のある方はポチっとして頂けると、私も全身から血を吹き出さずに済みます。
- 作者: 大角祐介
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2014/12/04
- メディア: Kindle版
- この商品を含むブログ (2件) を見る