bashを便利に使うためのいくつかのTIPS

人のオペレーションを見てるとそれぞれクセがあっておもしろいですよね!
というわけで自分がよく使うbashの便利機能をまとめてみました。

1つ前の作業ディレクトリに戻る

cd -で戻れます。

[mikeda@test01 tmp]$ cd
[mikeda@test01 ~]$ cd -
[mikeda@test01 tmp]$

pushd、popdを使えば2つ前でも3つ前でも戻れるのですが、めんどうなので基本コレだけ使ってます。

コマンドラインを移動する

この状態から

Ctrl+aを入力するとプロンプトが先頭に移動します。

Ctrl+eを入力すると末尾に移動です。

Ctrl+wを入力すると直前のワードを削除できます。

Ctrl+cで入力をキャンセルして次の行に移ります。


自分がよく使うのはこの4つです。

ヒストリをうまく使う

ヒストリ検索

Ctrl+rを入力するとヒストリ検索モードになります

[mikeda@test01 ~]$
(reverse-i-search)`':

テキストを入力するとヒストリ中でそれを含むものが出てきます。

[mikeda@test01 ~]$
(reverse-i-search)`cat': cat /etc/hosts

Ctrl+rをさらに入力すれば次々とヒストリをさかのぼっていけます。
そのままEnterで実行してもよし、ちょっといじって実行してもよし、です。


また「!文字列」でその文字列含む直前のコマンドを実行できます。

[mikeda@test01 ~]$ !cat
cat /etc/hosts
127.0.0.1               test01 localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
192.168.1.10    puppet-m.mikeda.jp
ヒストリ番号で実行

「!ヒストリ番号」でそのコマンドを実行できます

[mikeda@test01 ~]$ history |grep cat
  973  cat /etc/hosts
  974  cat /etc/passwd
[mikeda@test01 ~]$ !974
cat /etc/hosts
127.0.0.1               test01 localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
192.168.1.10    puppet-m.mikeda.jp
直前のコマンドの最後の引数を使う

「!$」で参照できます。

[mikeda@test01 ~]$ file /tmp/test.log
/tmp/test.log: ASCII text
[mikeda@test01 ~]$ cat !$
cat /tmp/test.log
test
  • 中身をcatで確認してからviで編集
  • ファイルサイズを確認してから圧縮、解凍

など、1つのファイルに連続してオペレーションを行う機会は多いので、ものすごく便利です。

直前のコマンドの全てを使う

「!!」で参照できます。「!$」に比べると使用頻度は落ちますが、
パーミッションエラーならsudoつきで再実行、

[mikeda@test01 ~]$ cat /etc/sudoers
cat: /etc/sudoers: 許可がありません
[mikeda@test01 ~]$ sudo !!
sudo cat /etc/sudoers
## Sudoers allows particular users to run various commands as
## the root user, without needing the root password.
...

直前のコマンドをwatchで繰り返し実行、

[mikeda@test01 ~]$ ls -l /tmp/test.log
-rw-rw-r-- 1 mikeda mikeda 5  3月 11 13:58 /tmp/test.log
[mikeda@test01 ~]$ watch !!

などでたまに使います。

ブレース展開

「{}」で囲んだ文字列をbashがいい感じに展開してくれる機能です。

[mikeda@test01 ~]$ echo {1..5}
1 2 3 4 5
[mikeda@test01 ~]$ echo /usr/{bin,src}
/usr/bin /usr/src


階層的なディレクトリを一気に作るとか

[mikeda@test01 tmp]$ mkdir -p work{1..3}/{bin,lib,conf}
[mikeda@test01 tmp]$ tree
.
|-- work1
|   |-- bin
|   |-- conf
|   `-- lib
|-- work2
|   |-- bin
|   |-- conf
|   `-- lib
`-- work3
    |-- bin
    |-- conf
    `-- lib

バックアップやアーカイブの作成コマンドを簡略化したりとか、

[mikeda@test01 tmp]$ cp -a work1{,.bak}
[mikeda@test01 tmp]$ tar czf work1{.tgz,}
[mikeda@test01 tmp]$ ls
work1  work1.bak  work1.tgz  work2  work3

たまに便利です。
でも一番使うのはfor文の引数ですね。

for文、while文を使う

コマンドラインでもよく使います。


for文はワイルドカードで複数ファイルに一括操作が1つの使い方。

for i in *.log;do mv $i /backup/;done

例がイマイチですね><


連続する数値を扱う場合はこういう例が多いかもですが

for ((i=0;$i<10;i++));do echo $i;done
for i in `seq 10`;do echo $i;done

自分はブレース展開で書いちゃうのがPerlっぽくて好きです。

for i in {1..10};do echo $i;done

追加で、指定ホストに次々SSHログインしていく例

for i in 192.168.1.{1..3} test-{web,db};do ssh $i;done


whileはreadと組み合わせて使うのがほとんどです。

[mikeda@test03 ~]$ cat hosts.list
192.168.1.51
192.168.1.52
[mikeda@test03 ~]$ while read l;do echo "## $l";ssh -n $l "hostname";done < hosts.list
## 192.168.1.51
test01
## 192.168.1.52
test02

readの使い方はいろいろ工夫の余地があります。

# 複数の変数で受け取る。区切り文字は空白文字で、あふれると最後の変数にまとめられる。
egrep -v '^($|#)' /etc/hosts | while read ip hosts;do echo $ip;done

# 区切り文字はIFS変数で変更可能
while IFS=: read user pass uid gid others;do echo $user $uid;done < /etc/passwd

無限ループはこんな感じで

[mikeda@test01 ~]$ while :;do date;sleep 3;done
2012年  3月 11日 日曜日 15:16:07 JST
2012年  3月 11日 日曜日 15:16:10 JST
2012年  3月 11日 日曜日 15:16:13 JST

while trueでもOKですよ!


ついでに、↑のIFSの使い方もそうですが、
一時的に変数を変更したい場合は単独で代入文を書くのではなく、

[mikeda@test03 ~]$ LANG=C
[mikeda@test03 ~]$ date
Sun Mar 11 15:01:07 JST 2012

コマンドの前に書きましょう。

[mikeda@test01 ~]$ LANG=C date
Sun Mar 11 14:55:49 JST 2012
[mikeda@test01 ~]$ date
2012年  3月 11日 日曜日 14:55:50 JST

へんな副作用が防げます。


終わりに

みんなそれぞれいろんなテクニックを持ってると思うので、
「こんな便利な機能があるよ!」というのがぜひあれば教えて下さい!