Edited at

Bash でファイルを使いこなす

Bash は多くの GNU/Linux ディストリビューションや macOS のデフォルトログインシェルとして普及しており、これらの OS では /bin/sh で起動するシェルも Bash の Bourne Shell 互換モード(なので Bash の POSIX に従っていない拡張機能は無効化される)だったりします。Debian では dash だ、とかいろいろありますが。この投稿では、Bash の便利機能だったり、Unix 系のシステムで使える便利な機能をまとめたいと思います。


パイプ

$ command1 | command2

おなじみの機能ですね。command1 の標準出力が command2 の標準入力につなげられます。UNIX 哲学に「すべてのプログラムはフィルタとして動作する」というものがありますが、この機能はその典型だと思います。

ちなみに、grep をパイプして less に渡したりすると、 grep から見て標準出力が tty ではなくなるので色がつかなくなります。それを防ぐには、expect というパッケージに含まれる unbuffer というコマンドに渡し、less-R オプションを付けると色がついたまま less で見られるようになります。

$ unbuffer command1 | less -R


リダイレクト

# 標準出力をファイル out.txt にリダイレクト

$ command >out.txt
# 標準エラー出力を標準出力にリダイレクト
$ command 2>&1
# 標準出力と標準エラー出力を /dev/null にリダイレクトして無視する
$ command >/dev/null 2>&1
# out.txt に追記する
$ command >>out.txt

ファイルから標準入力に流したり、標準出力や標準エラー出力を標準入力に流したりします。> では既存の内容に上書きする一方、 >> を使うと既存の内容に追記できます。.bashrc にリダイレクトで追記しようとして誤って > を使ってい、他の内容が消えてしまうみたいな事故を起こさないように注意が必要です(実体験)。

Bash では標準出力と標準エラー出力を同時にリダイレクトできます。

$ command &>/dev/null


プロセス置換

$ command <(command2) <(command3)

$ command >(command2)

呼び方は分かりません。 コメントで教えていただきました。

<(command) では command の標準出力からファイルとして読むことができ、 >(command) では commandの標準入力にファイルとして書き込むことができます。 Bash の機能なので sh では使えません。


tty をファイルとして扱う

tty は /dev/tty という仮想的なファイルとして存在しているのでファイルとして扱えます。

他にも以下のようなファイルかあります。


特殊ファイル


/dev/null

書き込んだ内容は破棄され、読もうとすると即座に EOF が返ってきます。コマンドの出力を無視するのによく使われています。

苦情を受け付けたくない場合に「不平不満は /dev/null に!」みたいな使い方もするらしいです。Wikipedia が言ってました。


/dev/zero

書き込んだ内容が破棄されるのは /dev/null と同じですが、 延々と \0 を詰め込んで返してきます。EOF は返さないみたいです。


/dev/random

ランダムなバイトを返します。デバイスなどから拾った環境のノイズを加工して返してくるので質は高い一方遅いです。書き込んだ内容は乱数生成のエントロピーとして使われます。


/dev/urandom

/dev/random と似ていますが、エントロピーが足りないと擬似乱数生成器で乱数を生成して返してくるので読み込みをブロックされません。GPG や SSL や SSH の鍵を生成する時以外はこちらを用いるべきと man に書いてあります。


/dev/tty

端末への出力や入力はここへの入出力に見えます。ファイルからの入力しか取らないプログラムたファイルへの出力しかしないプログラムに /dev/tty を渡すと端末から読むことができます。ただし、プログラムがファイルをシークする場合はうまく動かないので注意が必要です。/dev/stdin/dev/stdout/dev/stderr というのも存在します。こちらは /proc/self/fd/[0..2] へのシンボリックリンクになっています。/proc/self/fd/[0..2] それぞれの実際の出力先(tty、ファイルなど)へのシンボリックリンクになっています。