bashの思いもよらぬ便利ワザがよく記事になる。調べてみるとこの分野はだいぶ奥が深いようで、いつぞやvimrcを1か月ぐらいいじり続けた時のようなキリの無さを感じ始めたため、自分なりにmanをザクっと読んで使いそうなものだけまとめる。入門bashでも買おうかと思っていたが、とりあえずこんなもんでいい気がしてきた。
変数
- 代入時は
=
の前後にスペースを入れない - 配列代入は
()
で囲み、要素同士は半角スペースで仕切る - 変数展開は
${var}
- 配列要素nの展開は
${array[n]}
、@
を使うことで全要素参照 - 変数が存在しない場合のデフォルト値は
${var:-default}
で宣言可能
${var:=default}
とすると、var
が存在しない際はdefault
がvar
に代入される -
declare -A
による変数宣言で連想配列が使用可
$ declare -A hash=(["foo"]=1 ["bar"]=2)
$ echo ${hash["bar"]}
2
$ echo ${hash[0]}
1
$ echo ${hash[1]}
2
ブレース展開
連続する値や複数の値をコマンドライン上で展開する省略記法。
$ echo sample{01,02}
sample01 sample02
$ echo sample{1..5}
sample1 sample2 sample3 sample4 sample5
$ echo {a..c}
a b c
$ cp sample.txt{,.bk}; ls
sample.txt sample.txt.bk
キーバインド
Emacsライクなんだなと思っていたが、より正確にはGNU readlineを採用しているということになるらしい。一応set -o vi
でviライクなキーバインドも使えるようだが、なんだかコマンドラインに関してはEmacsライクな作法が染み付いてしまったので、viライクだと逆に違和感を覚える。Vimperator遣ってて、Thunderbirdもkeyconfigでviライクに操作しているというのに、慣れってこわい。
-
C-a
行頭へ移動 -
C-e
行末へ移動 -
M-f
1単語進む -
M-b
1単語戻る -
C-w
前1単語削除 -
C-u
カーソルより前方をすべて削除 -
C-k
カーソルより後方をすべて削除 -
C-y
ヤンク(C-w
等で削除した文字列をペースト) -
C-]
入力した文字を後方へ検索して移動 -
M-C-]
入力した文字を前方へ検索して移動 -
C-d
exit
コマンドと同義 -
C-l
clear
コマンドと同義
コマンド履歴
矢印キー上下(あるいはC-pとC-n)とhistory
コマンドだけが脳ではない。まず地味めなもので。
- ESC →
.
で直前の引数をカーソル下に展開 -
cd -
で直前のディレクトリへ移動
純粋にhistory
を使うものとしては以下。
-
M-<
最初の履歴に移動 -
M->
最後の履歴(現在行)に移動 -
!10
history 10番目を実行 -
!!
直前コマンドを再実行 -
!hoge
historyをhogeで前方一致検索し、最も実行日時が近いコマンドを実行 -
!?hoge
部分一致検索により同様の動作 -
^hoge^fuga
直前コマンドのhogeをfugaに換えて実行
!28
と打って何がでるかわからない博打がこわいなら:p
で実行されるコマンドを出力できる。
$ !28:p
ls /var/log/httpd/sample.log
$ !28
ls /var/log/httpd/sample.log
sample.log
:p
は 修飾子 と呼ばれるらしく、呼び出した履歴に対して任意の処理を実行できるものとして幾つか定義されている。調べてはみたが、たぶん覚えられないので使わなさそう。。
$ !28:p
ls /var/log/httpd/sample.log
$ !28:h # パス名から最後のスラッシュ以降を削除
ls /var/log/httpd
access_log error_log sample.log
$ echo !28:t # 最後のスラッシュ以降だけを残す
echo sample.log
sample.log
$ echo !28:r # サフィックスを取り除く
echo /var/log/httpd/sample
/var/log/httpd/sample
$ echo !28:e # サフィックスだけを残す
echo log
log
また履歴のコマンドラインから、任意の単語(引数)のみを抜き出すこともできる。 単語指示子 と呼ばれ、直前の引数を表す!$
が有名だが、他にもいろいろできる。ちなみに実際には!$
は直前の「最後の引数」を展開するものであり、複数引数があった場合には!^
で最初、!:n
でn番目の引数を指定できる。
$ ls dir | grep bar
bar
bar.txt
$ echo !:3 # 直前の3番めの単語(コマンド自体であるlsはカウントしない、パイプはカウントしている)
echo grep
grep
$ history
1 cp foo bar
2 mv bar dir/
3 ls dir | grep bar
4 echo grep
$ echo !2^ # history2番目のコマンドラインの最初の引数
echo bar
bar
スクリプト作成時に使えるもの
スクリプトに限定するものではないが、特にスクリプトを書くときに使いそうで覚えておきたいこと。
-
echo -e
バックスラッシュによるエスケープを解釈。 - 先頭に
set -e
でエラー出力時に即時停止。ただしパイプの中途のコマンドがエラーの場合には停止しない。パイプ中のエラーもNGとしたい場合にはset -o pipefail
を使う。 - バッククォート or
$(command)
でコマンド置換。
$(command)
の方がネストできてオススメと聞いたが、バッククォートも\
でエスケープすればネスト可能。 -
$((expression))
で算術式展開。
ヒアドキュメント
$ command <<any_word
foo
bar
baz
any_word
対話式
(追記 2015-11-20)
[Yy]と[Nn]いずれのケースも exit
を書いていたが、ループを抜けるだけであれば break
でよい。 exit
だとシェルスクリプト自体が終了する。
while read -p "question? [y/n] " yn ; do
case $yn in
[Yy]* ) {
...
break
};;
[Nn]* ) {
...
exit
};;
*) {
echo "please type again"
};;
esac
done