2014-07-13

超簡単!shoptでbashの”秘められた真のチカラ”を開放する 【サンプルあり】



shoptとは?

bashのオプションを設定するための、bash組み込みコマンド。
bashの秘められた力を開放することができる。

shopt
でオプション一覧を表示・確認することができる。

shopt -s {オプション名}
set。指定したオプションをONにできる。

shopt -u {オプション名}
unset。指定したオプションをOFFにできる。

bashのオプションは数多くあるが、
デフォルトでONにされていて普段意識する必要がないものや、
普段使いでは気にしなくていいものもある。

今回は、bashの全オプションの中から、
これらをおさえておけば9割オッケーなイケメンオプションを紹介しようと思う。


autocd

ディレクトリ名のみを入力したとき、 cdの引数に指定されたものとして扱う。
対話的シェルのみで有効。

autocd: OFF

$ shopt -u autocd

# ディレクトリ名のみを入力
$ /usr/local/
bash: /usr/local/: Is a directory

autocd: ON

$ shopt -s autocd

# ディレクトリ名のみを入力
$ /usr/local/
cd /usr/local/

# ディレクトリ名がcdの引数として扱われ、移動できた
$ pwd
/usr/local


cdable_vars

cd への引数でディレクトリでないものは変数の名前とみなし
その変数の値をcdの引数として使う。

# unkoを定義
$ export unko="/usr/bin/"

cdable_vars OFF

$ shopt -u cdable_vars

$ cd unko
bash: cd: unko: No such file or directory

 cdable_vars ON

$ shopt -s cdable_vars

# unkoというディレクトリが見つからないので、unkoという変数として扱われる
$ cd unko
/usr/bin/

# unko: /usr/bin/ に移動できている
$ pwd
/usr/bin



cdspell

スペルミスでcdに指定したディレクトリが見つからないとき、
本来移動したかったであろうディレクトリにちゃんとcdしてくれる。
対話的シェルのみで有効。

cdspell OFF

$ shopt -u cdspell

# ディレクトリ名にスペルミス がある
$ cd /usr/loacl/
bash: cd: /usr/loacl/: No such file or directory

# ディレクトリ名にスペルミス がある
$ cd /user/bin/
bash: cd: /user/bin/: No such file or directory

cdspell ON 

$ shopt -s cdspell

# ディレクトリ名にスペルミス がある
$ cd /usr/loacl/
/usr/local/
# 移動できている
$ pwd
/usr/local

# ディレクトリ名にスペルミス がある
$ cd /user/bin/
/usr/bin/
# 移動できている
$ pwd
/usr/bin



dotglob

. (ドット) で始まるファイル名をワイルドカード(パス名展開)のマッチ対象に含める。
明示的に .*  としなくても * だけで対象ファイルになる。

dotglob OFF

$ shopt -u dotglob

$ ls *
kuso
miso
tech

dotglob ON

$ shopt -s dotglob

$ ls *
.bash_profile
.bashrc
.ssh
.viminfo
.vimrc
kuso
miso
tech



extglob


基本的なワイルドカードでのパターンマッチング(*, ?, [a-z] など)に加えて、
さらに強力なワイルドカードの表現が使えるようになる。

通常のパターンマッチング

  • * ……… 任意の文字列にマッチ
  • ? ……… 任意の1文字にマッチ
  • [] ……… 括弧内のいずれか1文字にマッチ

extglobで使えるようになるパターンマッチング
  • ?(pattern-list) ……… 与えられたパターンが 0 回または 1 回現われるとマッチ
$ ls
ab.txt
abab.txt
ababab.txt


$ ls ?(ab)ab.txt
ab.txt
abab.txt

  • *(pattern-list) ……… 与えられたパターンが 0 回以上現われるとマッチ
$ ls
ab.txt
abab.txt
ababab.txt

$ ls *(ab)ab.txt
ab.txt
abab.txt
ababab.txt

  • +(pattern-list) ……… 与えられたパターンが 1 回以上現われるとマッチ
$ ls
ab.txt
abab.txt
ababab.txt

$ ls +(ab)ab.txt
abab.txt
ababab.txt

  • @(pattern-list) ……… 与えられたパターンに 1 回だけマッチ
$ ls
ab.txt
abab.txt
ababab.txt

$ ls @(ab)ab.txt
abab.txt

  • !(pattern-list) ……… 与えられたパターンのどれでもないものにマッチ
# 拡張子が.txt以外のファイルをリストアップする
$ ls
a.doc
a.gif
a.jpg
a.png
a.ppt
a.txt
a.xls
a.xlsx
b.txt
c.txt


$ ls !(*.txt)
a.doc
a.gif
a.jpg
a.png
a.ppt
a.xls
a.xlsx

# 拡張子が.txt以外のファイルをバックアップディレクトリに移動
$ mv !(*.txt) someBackupDir/

地味に便利。



globstar

** というワイルドカードが使われたとき、 該当ディレクトリ以下の
 サブディレクトリ、ファイル全てに再帰的にマッチする。
**の直後に / が続く場合には、 ディレクトリとサブディレクトリのみにマッチ。(再帰的でない)

globstar OFF

$ shopt -u globstar

# カレントディレクトリ直下の全ファイル・ディレクトリのタイムスタンプを更新
$ touch *

# カレントディレクトリ直下の全ファイル・ディレクトリのタイムスタンプを更新(↑と同じ)
$ touch **

globstar ON

$ shopt -s globstar

# カレントディレクトリ直下の全てのファイル・ディレクトリのタイムスタンプを更新
$ touch *

# カレントディレクトリ以下のファイル・ディレクトリのタイムスタンプを再帰的に更新
$ touch **



nocaseglob

ワイルドカードの展開を行うときに、 大文字と小文字を区別しない。

$ ls
AA
Aa

nocaseglob OFF

$ shopt -u nocaseglob

$ ls a[a-z]
ls: cannot access a[a-z]: No such file or directory

nocaseglob ON 
$ shopt -s nocaseglob

# 大文字小文字を区別しないマッチング。
#1文字目の a も大文字小文字区別されていないところも注目。
$ ls a[a-z]
AA
Aa


nocasematch

case や [[ でのパターンマッチのとき、大文字小文字を区別しない。

nocasematch OFF

$ shopt -u nocasematch

# マッチしない
$ if [[ "unko" = "UNKO" ]]; then echo match; fi

nocasematch ON

$ shopt -s nocasematch

# マッチする
$ if [[ "unko" = "UNKO" ]]; then echo match; fi
match

# ( [ 括弧が1つでの条件判定のとき) マッチしない
$ if [ "unko" = "UNKO" ]; then echo match; fi

おまけ: [ と [[ はどう違うの?
このへんも知っておくとひとつ上野プログラマになれそうよ♨


まとめ

エイリアスやキーマッピング、環境変数でシェルの利便性を高めている人は多いが、
シェルのオプションは意外とそこまで使われていないような気がする。。

気になったオプションがあれば試してみて、
もし気に入れば .bashrc, .bash_profileあたりに追加しておくと幸せになれると思う。