概要
bashの記法は独特なものが多く毎回ググってしまうのでまとめて(と言いつつまとまりがないですが。。。)おこうと思います。
ある程度まとまってからpostしようとか思ってたらごちゃごちゃになっちゃいました。
bashで使えるという意味なのでposixシェル共通のネタも混ざってます。
随時更新します。参考になれば幸いです。
参考
man bash
- リファレンスマニュアル
- Advanced Bash-Scripting Guide
カッコ色々
bashでは色々なカッコがありますが、よく違いが分からず使っていたりするのでまとめてみます。
[]と[[]]
[]はtestコマンドのaliasです。[[]]じゃないとできないこととしては、以下のようなものがあります。
-
空白を含む文字列をクォートしなくてOK
クォート不要var='abc 123' # []の中だとクォートしないとエラーになる [ $var = 'abc 123' ] && echo 'ok' -> brace.sh: line 6: [: too many arguments [ "$var" = 'abc 123' ] && echo 'ok' -> ok # [[]]の中だとクォートしなくてもOK [[ $var = 'abc 123' ]] && echo 'ok' -> ok
-
=~で正規表現が使える
正規表現が使えるvar='abc 123' # [[]]の中だと正規表現が使える [[ $var =~ [a-z]{3}[[:space:]][1-9]{3} ]] && echo 'ok' -> oke
bashの正規表現についてはこちらが参考になります。
-
パターンマッチもできる
パターンマッチもできるvar='abc 123' # [[]]の中だとパターンマッチができる [[ $var = abc* ]] && echo 'ok' -> ok [ $var = abc* ] && echo 'ok' -> brace.sh: line 18: [: too many arguments
-
AND条件OR条件に&&や||が使える
OR条件に||が使える# []の中だとOR条件は-oを使う [ "$var" = 'abc 234' -o "$var" = 'abc 123' ] && echo 'ok' -> ok # [[]]の中だとOR条件に||が使える [[ $var = 'abc 234' || $var = 'abc 123' ]] && echo 'ok' -> ok
その他詳しくはこちら
ちなみに基本的には[]はPOSIXシェル準拠で[[]]はPOSIX準拠ではないです。
が、[[]]もbash以外にzshやkshでも実装されているものが多いので移植性を考えて利用を控えるとかはしなくても大丈夫なんじゃないかと思っています。
あと、[]は配列のインデックスを指す場合にも使いますが、そちらは説明するまでもないと思うので省略します。
()と(())
-
()は配列を定義するときに使います。
配列定義var=(a b c) echo ${var[2]} -> c
-
(())は演算に使います。
for文のカウンタとして使うfor ((i=0;i<3;i++)) do echo $i done -> 0 1 2
インクリメントvar=1 ((var++)) echo $var -> 2
個人的によく間違えちゃうんですが、変数を定義するときは(())から含める必要があります。
((var2=$var + 3))
と書くのが正しい($varはvarでもOKです)んですが、よくvar2=(($var + 3))
とか書いてエラーになっちゃいます。
この辺りは$(())のところでも後述します。
{}と{{}}
-
変数展開
{}は$を付けて変数参照やら置換に使いますね。詳しくは後述します。 -
様々な展開
あとは変数に限らず色々な展開ができます。
例えば以下のようにfor文のカウンタを展開することができます。for文for i in {a..c} do echo $i done -> a b c
この展開は結構便利でcpやmv使うときに重宝します。
例えばファイルのバックアップを取るときは以下のようにできます。
```bash:cpと{}を使ってバックアップ
cp /path/to/file{,_old}
```
とかやると/path/toにfileのコピーとしてfile_oldが出来上がります。
フルパス2個打つとか無駄なことをしなくて済みます。
-
コマンドをまとめる
{}を使うと複数のコマンドをひとまとめにできます。コマンドをまとめる{ echo hoge echo fuga echo piyo } > echo.log
ログ出力とかで重宝します。
全部のコマンドの後ろにリダイレクトを書くよりもキレイにできます。
続いて{{}}ですが、これは見たことないです。。。これって何かありますでしょうか?
$()と$(())
-
$()はコマンド展開です。``と同じ意味です。
たとえば/path/toにある各ファイルに対して何らかの処理を行う場合は以下の通りです。コマンド展開for i in $(ls /path/to) do echo $i done
-
$(())は演算で使います。(())と違ってインラインで使えます。
$(())の演算echo $((1+3)) -> 4 # echo ((1+3))はエラーになる var=1 var2=$(($var + 2)) echo $var2 -> 3 # var2=((var + 2))はエラーになる
この辺りは混同しがちなので要注意ですね。
''と""
カッコではないですが''と""の違いは変数が展開されないかとされるかの違いです。
var='abc'
echo '$var'
-> $var
echo "$var"
-> abc
宣言色々
bashの変数はデフォルトではグローバルです。
まずは以下を例にします。
#!/bin/sh
var1='var1 initial'
function func1 {
var1='var1 changed'
var2='var2 initial'
echo $var1 # 3. 関数外で定義したグローバルな変数var1を書き換えたため'var1 changed'が表示される
echo $var2 # 4. 関数内で定義したグローバルな変数var2の初期値'var2 initial'が表示される
}
echo $var1 #1. この時点では関数呼び出し前のため'var1 initial'が表示される
echo $var2 #2. この時点では関数呼び出し前のため''(空文字)が表示される
func1
echo $var1 #5. グローバルなvar1変数をfunc1関数内で書き換えたため、'var1 changed'が表示される
echo $var2 #6. func2内で定義したグローバルな変数var2の値が参照できるため、'var2 init'が表示される
挙動はコメントに書いたとおりですが、実行すると以下の結果が得られます。
var1 initial
var1 changed
var2 initial
var1 changed
var2 initial
変数宣言にlocalをつけて関数内localな変数にする
変数はlocalで宣言することでローカル変数とすることができます。
上記のスクリプトを以下のように書き換えます。
#!/bin/sh
var1='var1 initial'
function func1 {
local var1='var1 changed'
local var2='var2 initial'
echo $var1 # 3. 関数で定義したローカル変数var1の値'var1 changed'が表示される
echo $var2 # 4. 関数内で定義したローカルな変数var2の初期値'var2 initial'が表示される
}
echo $var1 #1. グローバルな変数var1の値'var1 initial'が表示される
echo $var2 #2. var2は未定義のため''(空文字)が表示される
func1
echo $var1 #5. func1内で書き換えたのはローカル変数のため、グローバルなvar1変数の値は変わらず'var1 initial'が表示される
echo $var2 #6. func2内で定義したvar2はローカル変数のため、値が参照できず''(空文字)が表示される
これまた挙動はコメントに書いたとおりですが、実行すると以下の結果が得られます。
var1 initial
var1 changed
var2 initial
var1 initial
変数宣言時に型指定する
変数宣言時にdeclare -i var1
等とすると型を指定することができます。(ローカル変数の場合local -i var1
等とできます。)
-i
はintegerの意味で整数値を割り当てるようになります。
declare -i var1=123
echo $var1 # 123
var1=hoge
echo $var1 # 0
文字列を代入した場合にエラーにしてくれないのはちょっと残念ですね。
ちなみに代入する値が数式の場合は計算されます。
var1=4/2
echo $var1 # 4/2
declare -i var1=4/2
echo $var1 # 2
その他使えるオプションはhelp declare
で見ることができます。
(ちなみにbashのビルトインコマンドはmanでは出てこないのでhelpで見ます。cdとかもそうですね。)
変数宣言時にreadonlyを付けて読み取り専用変数(定数)にする
変数はreadonlyとして宣言することで読み取り専用にすることができます。
例えば、以下のスクリプトがあったとき、
#!/bin/sh
readonly var1='hoge'
echo $var1
var1='fuga'
echo $var1
上記を実行すると、以下の結果が得られます。
hoge
readonly.sh: line 6: var1: readonly variable
hoge
var1の値は書き換えられずエラーになり、2回目のecho $var1
では元の値が表示されます。
ちなみにdeclare -rとして宣言してもreadonlyと同じ効果が得られます。
exportを使って別のシェルプロセスに変数を渡す
通常、あるシェルで定義した変数は別のシェルでは読めません。
しかし、exportを付けて宣言することで他のシェルに渡すことが可能になります。
たとえば以下のスクリプトがあったとき、
#!/bin/bash
echo $var1
シェルから上記のスクリプトを実行すると以下のような結果になります。
var1='hoge'
bash export.sh
#var1の値は別のシェルには渡らないため何も表示されない
export var1='hoge'
bash export.sh
-> hoge
#exportした変数var1の値は別のシェルに渡るため、親のシェルで設定した値が表示される
sourceを使って別のシェルから変数をもらう
上と逆のパターンです。
例えば以下のスクリプトがあった場合、
#!/bin/bash
var1='hoge'
実行結果は以下のようになります。
$ bash source.sh
$ echo $var1
# source.shで定義した変数は受け取れないため何も表示されない
$ source source.sh
$ echo $var1
->hoge
#sourceコマンドで読み込んだスクリプト内で定義した変数var1の値が表示される。
シェル上での実行というよりは複数ファイル間で変数の受け渡しをする際によく使いますね。
ちなみにsource
は.
で代替できます。
変数色々
bashの変数には様々なものがあります。
$系
基本的には引数やらコマンド実行結果やらを示します。
以下のdollar.shを./dollar.sh abc 123
と実行した場合をコメントで示します。
#!/bin/bash
echo $0
# 実行コマンド。今回の場合はdollar.sh
echo $1
# 一つ目の引数。今回の場合はabc
echo "$*"
# 全ての引数。今回の場合はabc 123
echo "$@"
# 全ての引数。今回の場合はabc 123。上記との違いは後述
echo $#
# 引数の数。今回の場合は2
echo $$
# 実行中のプロセスID
echo $!
# 前回実行コマンドのプロセスID。今回の場合dollar.shを実行前のコマンドのPID
echo $?
# 前回実行コマンドの実行結果。成功の場合は0
echo $-
# スクリプト内で有効になっているフラグを表示します。
echo $_
# 実行シェルが取れます。./doller.shと実行していれば./doller.shが、bash doller.shと実行していれば/bin/bashが取れます。
フラグはこちらを参照してください。
$*
と$@
の違いは前者は引数全てを一つの文字列として扱うのに対して、後者はそれぞれ別に扱う点です。
基本的には$@
を使うと良いと思います。
#!/bin/bash
for i in "$*"
do
echo $i
done
./asterisk.sh 123 abc
-> 123 abc
#!/bin/bash
for i in "$@"
do
echo $i
done
./at.sh 123 abc
-> 123
abc
-
さらにコマンドラインでは以下のような$変数が使えます。
-
!$
で前回実行コマンドの最後の引数を取得```bash:前回実行コマンドの最後の引数を取得 less /path/to/file # とりあえず参照したけどやっぱり編集したいとかなったときは以下のようにする vi !$ ```
-
!!で前回実行コマンドの全体を取得
```bash:前回実行コマンド全体を取得 service httpd restart # とか実行したけどsudoしなきゃダメだったときは以下のようにする sudo !! ```
!!は$入ってないですねw
それ以外
$系以外にも色々な組み込み変数があります。
有名なのだと$HOMEとかですね。
書ききれないのでこの辺を参考にしてもらえればと思います。
展開色々
変数操作
bashでは${}の中で色々な展開や置換等の変数操作が行えます。
例として、path=/hoge/hoge/fuga/FUGA/piyo
のとき、
-
文字数を取得
echo ${#path} -> 25
-
部分文字列を取得
echo ${path:1:4} -> hoge # 2文字目(インデックスが0始まりのため1は2文字目)から4文字を取得
-
一つ目のhogeをhageに置換
echo ${path/hoge/hage} -> /hage/hoge/fuga/FUGA/piyo
-
全てのhogeをhageに置換
echo ${path//hoge/hage} -> /hage/hage/fuga/FUGA/piyo
-
小文字を大文字に変換
echo ${path^^} -> /HOGE/HOGE/FUGA/FUGA/PIYO
-
大文字を小文字に変換
echo ${path,,} -> /hoge/hoge/fuga/fuga/piyo
-
ファイル名取得
echo ${path##*/} -> piyo
-
ディレクトリ取得
echo ${path%/*} -> /hoge/hoge/fuga/FUGA
リダイレクトとパイプ色々
基本
>
がファイルへのリダイレクト、>>
が上書き、|
がパイプというのはさすがに説明不要かと思います。
-
標準エラー出力をリダイレクト
ls /home/bin 2> hoge.log
-
標準出力と標準エラー出力の両方をリダイレクト
ls /home/bin /home/user1 &> hoge.log
もしくは
ls /home/bin /home/user1 >& hoge.log
もしくは
ls /home/bin /home/user1 > hoge.log 2>&1
-
teeで標準(エラー)出力とファイル両方に出力
ls /home/user1 | tee hoge.log
execを使った色々
-
出力をファイルに書く。
exec &>file
とすると以降のコマンド実行結果は全てfileに書かれます。
ただしエコーバックがなくなるので後述のプロセス置換、もしくはそもそもscriptコマンドを使ってしまった方が良いです。 -
任意のファイルディスクリプタを開く。(出力)
3>
等とすることで出力用に任意のファイルディスクリプタを開くことができます。コマンド実行結果をファイルに書くexec 3>file echo "hoge" >&3 exec 3>&-
上記のように実行するとhogeがfileに書かれます。
最後は3>&-
として忘れずにファイルディスクリプタを閉じましょう。
なお、3は標準出力(1)と標準エラー出力(2)以外の任意の数字でOKです。
-
任意のファイルディスクリプタを開く。(入力)
3<
等とすることで入力用に任意のファイルディスクリプタを開くことができます。fileからgrepするexec 3<file grep "hoge" <&3 exec 3<&-
fileからhogeという文字列をgrepしています。
最後は忘れずに閉じましょう。
-
任意のファイルディスクリプタを開く。(入出力)
3<>
等とすることで入出力用に任意のファイルディスクリプタを開くことができます。入出力echo "hoge" > file echo "fuga" >> file echo "piyo" >> file exec 3<> file read var1 <&3 echo $var1 #hoge echo 'puyo' >&3 exec 3>&- exec 3<&-
とやるとfileの中身は
```
hoge
puyo
piyo
```
になります。readで読んだ位置からpuyoを書くためです。
-
webページをgetする
上記を応用するとこんなことができます。yahooをgetexec 3<>/dev/tcp/www.yahoo.co.jp/80 echo -e "GET / HTTP/1.1\n\n" >&3 cat <&3
実は順番はどうでも良い
もはや小ネタレベルですが、実は下の3つはどれも同じ意味です。
echo 'hoge' >hoge.txt
>hoge.txt echo 'hoge'
echo >hoge.txt 'hoge'
read色々
readコマンドを使うとファイルとか変数から値を読むことができます。
field1 \field2 field3 fiedl4
f1 \f2 f3 f4
#!/bin/bash
while read var1 var2
do
echo $var1
echo $var2
done < read.txt
field1
field2 field3 fiedl4
f1
f2 f3 f4
いらないフィールドを捨てる
ファイルの中に不要なフィールドある場合は_
で捨てることができます。
(_
じゃなくても任意の文字列で大丈夫ですがgolangっぽく_
にしてみましたw)
#!/bin/bash
while read var1 var2 _
do
echo $var1
echo $var2
done < read.txt
field1
field2
f1
f2
エスケープ回避
上記の通りテキストに\
が含まれる場合、エスケープされてしまいます。
テキストに書かれている通り出力する場合は-rを付けます。
#!/bin/bash
while read -r var1 var2 _
do
echo $var1
echo $var2
done < read.txt
field1
\field2
f1
\f2
変数を読む
ヒアストリング(後述)とかを使うと変数から値を読むことができます。
#!/bin/bash
var='a b c d'
read -r var1 var2 _ <<<$var
echo $var1
echo $var2
その他
-
IFSを使うと区切り文字を変えることができます。
IFS=- read -r var1 var2 <<< "a-b-c-d-e"
-
-aを使うと値を配列に読み込むことができます。
IFS=- read -ra parray <<< "a-b-c-d-e"
ということで例によって詳しくはhelp read
でお願いしますw
&&や||で条件が書ける
簡単な条件判定なら&&や||を使うのがオススメです。
# 条件がtrueの場合に実行
[ 1 -lt 2 ] && echo "1 is less than 2"
-> 1 is less than 2
# 条件がfalseの場合に実行
[ 1 -gt 2 ] || echo "1 is NOT greater than 2"
-> 1 is NOT greater than 2
# if else的な
[ 1 -gt 2 ] && echo "1 is greater than 2" || echo "1 is NOT greater than 2"
-> 1 is NOT greater than 2
ただし複雑な条件を書く場合は可読性を考えてif文を使ったほうが良いと思います。
ヒアドキュメントとヒアストリング
ヒアドキュメント
<<
はヒアドキュメントと呼ばれ、文字列リテラルをコマンドに渡したりすることができます。
sqlplusやmysqlコマンド等でインラインでSQL実行したい場合等によく使います。
-
基本
基本的な使い方は以下の通りです。_EOF_
は任意の文字列でOKです。
mysqlのインタラクティブなシェルは開かず、sqlが実行されて結果がターミナルに返ります。ヒアドキュメントmysql -u user -ppassword -D database <<_EOF_ select * from test_table where id=1 _EOF_
-
リダイレクトとパイプ
リダイレクトとパイプは以下のようにします。リダイレクトmysql -u user -ppassword -D database <<_EOF_ > output.log select * from test_table where id=1 _EOF_
パイプmysql -u user -ppassword -D database <<_EOF_ | grep hoge select * from test_table _EOF_
-
エスケープ
ヒアドキュメントには変数を渡すこともできます。変数渡しid=1 mysql -u user -ppassword -D database <<_EOF_ select * from test_table where id=${id} _EOF_
変数をエスケープして文字列リテラルとして渡したい場合は以下のよう_EOF_
の前に\
を付けます。
```bash:エスケープ
id=1
mysql -u user -ppassword -D database <<\_EOF_
select * from test_table where id=${id}
_EOF_
```
-
インデント
インデントしたい場合、以下のように書くとエラーになってしまいます。インデントできないfor i in {1..2} do cat << _EOF_ loop $i _EOF_ done
インデントしたい場合は以下のように<<-とします。
```bash:インデント
for i in {1..2}
do
cat <<- _EOF_
loop $i
_EOF_
done
```
ヒアストリング
<<<
はヒアストリングと呼ばれ、ヒアドキュメント同様文字列をコマンドに渡したりすることができます。
mysql -u user -ppassword -D database <<<"select * from test_table"
ただしインデントを付けたりはできません。(実は方法があったら教えてください)
可読性等を考えると基本的には1行のとき以外はヒアドキュメントの方が良いと思っています。
ちなみにリダイレクトとパイプは問題なくできます。
mysql -u user -ppassword -D database <<<"select * from test_table" > output.log
mysql -u user -ppassword -D database <<<"select * from test_table" | grep hoge
プロセス置換
プロセス置換とはプロセスの結果を一時ファイルのようにコマンドに渡したりできる機能です。
<()を使って一時ファイル不要のdiff
一番よく使うのがこのケースだと思います。
こんな感じのことができます。
diff <(sort file1.txt|uniq) <(sort file2.txt|uniq)
file1の中身とfile2の中身をsortしてuniqしたものを比べてます。
プロセス置換を使わないと一時ファイルに吐き出したものをdiffする必要があります。
>()を使ってコマンド出力結果をログに出力
>()
は個人的にはあまり使いません。
以下のようにすると以降のコマンド実行結果は全てログにも出力されるようになります。
# 標準出力
exec 1> >(tee -a out.log)
# 標準エラー出力
exec 2> >(tee -a err.log >&2)
>()
はこれくらいでしか使わない上、この用途もscriptコマンド使ってしまうことが多いです。
標準出力と標準エラー出力を分けたい(もしくはどちらかのみ取りたい)ケースでたまに使います。
一番よく使うケースとしてはstraceの実行結果をログに出すときに標準エラー出力に出すパターンで使ったりします。
コマンド履歴
historyに日時を残す
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
historyコマンドの結果が変わります。
~/.bash_historyのエントリーには#付きでUNIXタイムが刻まれます。
現在のセッションの履歴を残さない
unset HISTFILE && exit
履歴全削除
HISTFILESIZE=0 && exit
スクリプトにセットする推奨オプション
上でも少し出てきましたが、setコマンドを使うとbashの挙動を制御することができます。
bashのスクリプトを実行するときに個人的によく付けるオプションはset -euo pipefail
です。
それぞれ以下の通りです。
-e
スクリプト内のコマンドで1つでもエラー(0以外の戻り値を返すもの)があるとスクリプトをそこで停止します。
#!/bin/bash
ls /path/to/nonexist
echo hoge
-> ls: cannot access /path/to/nonexist: No such file or directory
hoge # lsでエラーになってもhogeが出力される
#!/bin/bash
set -e
ls /path/to/nonexist
echo fuga
-> ls: cannot access /path/to/nonexist: No such file or directory
# lsがエラーでスクリプトが終了するためecho fugaは実行されない
ここで問題になるのが、正常終了でも戻り値が0でないコマンドです。
また、実行結果がエラーでも一時的に無視したいケースもあるかと思います。
そんなときはコマンドの後ろに|| trueを付けるか、一時的に-eを無効にします。
# 回避パターン1
/command/that/returns/nonzero || true
# 上は必ず戻り値($?)が0になる
# 回避パターン2
set +e
/command/that/returns/nonzero
set -e
-u
未定義の変数呼び出しを行うとエラーとします。変数名の打ち間違い等で意図した挙動にならないなんてことを防いでくれます。
/bin/bash
var='123'
var2=${var1}'abc' #間違えてvarではなくvar1としてしまった
echo $var2
# var1は空なのでabcが出力されてしまう
set -u
var2=${var1}'abc' #ここで'var1: unbound variable'というエラーになる
echo $var2 # set -eもつけていればここが出力されずに停止する
ここで困るのが$1
等のコマンドラインからの引数を受け取る際に、引数が任意の場合です。
必ず引数を渡すなら良いですが、任意の場合は$1
などを使った際に未定義でエラーになってしまい使い勝手が悪いです。
そんなときはデフォルト値を使うと良いです。
#!/bin/bash
set -u
var=${1:-default value}
echo $var
上記を./default.sh
と実行した場合はdefault value
が表示され、./default.sh hoge
と実行した場合はhoge
と表示されます。
-o pipefail
パイプでコマンドを繋げた時にパイプのどれか1つでも0以外の戻り値を返したらその戻り値(複数あった場合は最も右側)を返すというものです。
デフォルトだと最後の戻り値が返るため、エラーハンドリングが正しくできなかったりします。
sort /path/to/nonexist | uniq
echo $?
# uniq自体は成功するため0が返る
set -o pipefail
sort /path/to/nonexist | uniq
echo $?
# sortが失敗した戻り値の2が返る
スクリプトを書く際は上の3つを付けるようにしています。
他にもデバッグ時には-xや-vも付けます。
EXITをフックする
スクリプト内で作った一時ファイルの削除等、エラーが起きた場合でも必ず実行したい処理というものはよくあると思います。
このような場合はEXITをフックして処理を実行することができます。
例えば以下のスクリプトは処理開始時に作成した一時ファイル格納ディレクトリをスクリプト終了時に必ず削除します。
#!/bin/bash
# 一時ファイルを格納するディレクトリを作成
tmpfile=$(mktemp -d)
# スクリプト終了時に必ず実行したい処理を記述
function finally {
rm -rf $tmpfile
}
# trapコマンドでEXITシグナル受信時にfinally関数が実行されるようにする
trap finally EXIT
echo 'start' > $tmpfile/file1
cat $tmpfile/file1
補完
bash completion
bashの補完は非力なのでbash-completionを導入すると様々なコマンドの補完ができるようになります。
sshコマンドやserviceコマンド等の補完ができるようになるため導入必須かと思います。
対応しているコマンドは/usr/share/bash-completion/completions/以下に設定ファイルが置かれます。
手元の環境(Ubuntu14.04)で見ると500コマンド以上が対応しているようです。
独自コマンドを追加したい場合はこちらにやり方が書かれています。
結構簡単に追加できます。
rlwrap
sqlplusやmysql、redis等、独自のシェルが起動するコマンドを実行するとコマンド履歴や補完が使えなくなります。
rlwrapを導入すると履歴や補完が使えるようになります。
導入はapt-get install rlwrap
やyum install rlwrap
するだけです。(CentOSの場合はepelレポジトリが必要です)
rlwrapは文字通りreadlineをラップするだけなのでデフォルトだと補完といっても標準のシェルのコマンド補完しかできません。
なので例えばsqlplusでsqlを補完したい場合などはこちらの拡張を入れたりするとより便利になります。
GLOBIGNORE
GLOBIGNOREを使うとワイルドカード利用時の除外ファイルを指定できます。
例えば、末尾にorgがついてるファイルを除外してlsしたいとか、testって文字が入ったファイルを除外してvimで開きたいとかって時に便利です。
$ ls
fuga.go fuga_test.go hoge.go hoge_test.go
$ GLOBIGNORE="*test*"
$ vi *
2 files to edit
-> hoge.goとfuga.goだけ開ける
それでも不満があれば
実行速度とか機能で不満が出てきたらzshとかに移行しましょうw
以上です。
随時更新します。