トラック
/
Bash
Bash
/
シラバス
/
リダイレクト
リダ

リダイレクト の Bash

{other: "%{count}個の演習"}

リダイレクトについて

コマンドラインインターフェースの世界では、プログラムは次の3つの標準データストリームとやり取りすることがよくあります:

  1. 標準入力(stdin):プログラムが入力を受け取る場所です(通常はキーボードから)。
  2. 標準出力(stdout):プログラムが通常の出力を送る場所です(通常はターミナル画面へ)。
  3. 標準エラー出力(stderr):プログラムがエラーメッセージを送る場所です(通常はターミナル画面へ)。

これらはパイプラインとコマンドリストの章で紹介したことを思い出してください。

Note

パイプラインはリダイレクトの一種と考えることができます。あるプログラムの標準出力が、別のプログラムの標準入力へ直接送られるからです。 パイプラインについてはすでに説明しました。 このコンセプトでは、ファイルへのリダイレクトとファイルからのリダイレクトを扱います。

シェルのリダイレクトは、これらのストリームの送り先を変えられる強力な仕組みです。 プログラムがキーボードから読み込んだり画面に書き込んだりする代わりに、ファイルから入力をリダイレクトしたり、出力をファイルへ送ったりできます。 これにより、プログラムがデータとやり取りする方法を、柔軟に、細かく制御できます。

主なリダイレクト演算子

よく使うリダイレクト演算子と、それぞれの働きを紹介します。

>(出力のリダイレクト)

  • 目的:コマンドの標準出力(stdout)をファイルへリダイレクトします。

  • 動作:

    • ファイルが存在しなければ、新しく作成されます。
    • ファイルが存在する場合、その内容は上書きされます。
  • 例:

    # Sends the output of 'ls -l' to 'file_listing.txt'
    ls -l > file_listing.txt
    
Caution

リダイレクトは、コマンドが実行される前に行われます。 つまり、読み込みたいファイルと同じファイルへリダイレクトすることはできません。

date > date.txt         # populate the file with the current date
cat date.txt > date.txt # 'date.txt' is now empty!

上の例の2つ目のコマンドでは、次のことが起こります。

  1. まずBashが、リダイレクトで指定されたファイルを切り詰めます。 これにより以前の内容が消え、空のファイルになります。
  2. 次にBashが、空になったファイルを読み込みます。
  3. そしてBashがその内容(つまり何もない状態)をファイルへ書き戻します。

>>(出力の追記リダイレクト)

  • 目的:コマンドの標準出力(stdout)をファイルへ追記します。

  • 動作:

    • ファイルが存在しなければ、新しく作成されます。
    • ファイルが存在する場合、出力はファイルの末尾に追加されます。
  • 例:

    # Adds "Another line" to the end of the file
    echo "Another line" >> file_listing.txt
    

<(入力のリダイレクト)

  • 目的:コマンドの標準入力(stdin)をファイルからリダイレクトします。

  • 動作:コマンドは、キーボードではなく指定されたファイルから入力を受け取ります。

  • 例:

    # 'tr' reads from 'lowercase.txt' and
    # output is redirected to 'uppercase.txt'
    tr 'a-z' 'A-Z' < lowercase.txt > uppercase.txt
    

2>(エラーのリダイレクト):

  • 目的:コマンドの標準エラー出力(stderr)をファイルへリダイレクトします。
  • 動作:エラーメッセージは、ターミナルではなく指定されたファイルへ送られます。
  • 例:
    # Error message from 'rm' is sent to 'error_log.txt'
    rm non_existent_file 2> error_log.txt
    

2>>を使えば、標準エラー出力をファイルへ_追記_することもできます。

そのほかのリダイレクト

stdinとstderrの両方をまとめるリダイレクトもあります。 詳しくはマニュアルを参照してください。

/dev/null

/dev/nullは特別なファイルで、次のような性質があります。

  • 読み込むときは空のファイルになります。
  • 書き込まれたデータはすべて捨てます。

「ビットバケット」と呼ばれることもあります。 出力やエラーを抑えるのに便利です。

some_command > /dev/null  # Discards stdout
some_command 2> /dev/null # Discards stderr

# Using /dev/null as input will prevent the command
# from reading data from the keyboard
some_command < /dev/null

リダイレクトの組み合わせ

複数のリダイレクトを一度に指定できます。

some_command < input.txt > output.txt 2> error.txt

リダイレクトはコピーできます。

# send stderr to the same destination as stdout
some_command > output.txt 2>&1

2>&1を見かけたら、「stderrを、stdoutが現在指している場所へリダイレクトする」と読んでください。 Bashはリダイレクトの指示を厳密に左から右へ処理します。つまり、次のようなことができます。

# redirect stdout to 'output1.txt'
# redirect stderr to the same place
# then change stdout to 'output2.txt'
some_command > output1.txt 2>&1 > output2.txt
Advanced

ファイルディスクリプター

シェルプログラミングやLinux/Unixのようなオペレーティングシステムの文脈では、ファイルディスクリプター(FD)は、開かれたファイルやI/O(入出力)リソースを識別・操作するための非負の整数です。 オペレーティングシステムが、開いているファイルやデータストリームを管理するために使う、ラベルや参照番号のようなものだと考えてください。

リダイレクトの左側に書かれている数字が、ファイルディスクリプターです。

標準のI/Oストリームには、最初の3つのファイルディスクリプターが割り当てられています。

  • 標準入力はFD 0
  • 標準出力はFD 1
  • 標準エラー出力はFD 2

新しいファイルディスクリプターは、execコマンドとリダイレクト演算子を使って設定・作成できます。

# create FD 3 as a copy of stdout
exec 3>&1
# send stdout to a log file
exec > log.txt

# then redirect both stdout and file descriptor 3
echo "some debug message" >&3  # displayed in the terminal
some_command  2>&1 # stdout and stderr send to 'log.txt'

このテクニックはかなり入り組んで見えますが、スクリプトがほかのソフトウェアから実行され、標準出力がそのソフトウェアに自動的に取り込まれるような状況では、とても役立ちます。 このトラックの単体テストを実行するために使われるbatsコマンドは、まさにこのように動作します。batsはテストの標準出力と標準エラー出力を取り込みますが、FD 3へ送られたデバッグメッセージはターミナルに表示されます。

まとめ

リダイレクトはなぜ役立つのでしょうか?

  • 出力の保存:コマンドの結果を保存して、あとで確認したり処理したりできます。
  • ログの記録:デバッグのためにエラーメッセージを残せます。
  • 自動化:あるコマンドの出力を別のコマンドの入力として使うことで、コマンドをつなげられます。
  • フィルタリング:不要な出力を捨てられます。
  • バッチ処理:手で入力する代わりに、ファイルからデータを処理できます。
  • スクリプト作成:堅牢なシェルスクリプトを書くには、リダイレクトが欠かせません。

シェルのリダイレクトを使えば、プログラムがデータとやり取りする方法を細かく制御でき、複雑なワークフローを組み立てたり、情報を効率よく管理したりできます。

GitHubで編集 リンクは新しいウィンドウまたはタブで開きます