【bash】リダイレクトについての色々

bashでのリダイレクト方法について、すぐ忘れるのでまとめました。

リダイレクトって何だろう?(ざっくり説明)

コマンドやプログラム等への入出力には以下のようなものがあり、これらは通常画面に結果が表示されます。

  • 標準入力: キーボードからの入力(出力先:画面)
  • 標準出力: 実行結果の表示(出力先:画面)
  • 標準エラー出力: 画面へのエラー結果の表示(出力先:画面)

この表示先を変更することをリダイレクトといいます。

実際の例

「cat」コマンドを使用して実際の例を見てみます。

  • 「cat」に標準入力で「hello.txt」と「world.txt」(存在しないファイル)を入力
  • 「hello.txt」の内容を標準出力で表示
  • 存在しない「world.txt」は標準エラー出力でエラーメッセージを表示
$ cat hello.txt world.txt   # hello.txt world.txt が標準入力
Goodbye World   #  標準出力
Hello World     #  標準出力
cat: world.txt: No such file or directory  # 標準エラー出力

ファイルへの上書きと追加のリダイレクト(出力)

コマンドの実行結果をファイルにリダイレクト(出力)させる方法です。

# 上書き ファイルがない場合は新規作成
コマンド > ファイル 

# 追記  ファイルがない場合は新規作成
コマンド >> ファイル    

「>」で上書きした場合、すでに書き込まれているファイルの内容は削除されてしまします。

「>>」で追記した場合は、すでに書き込まれているファイルの内容に追記で書き込みが行われます。(既存のデータはのこります)

リダイレクト先に指定したファイルが存在しない場合は、新規にファイルが作成されます。

標準出力・標準エラー出力のリダイレクト

リダイレクトでファイルに書き込みを行う場合、「>」や「>>」だけ指定すると標準出力のみしかリダイレクトされません。

標準エラー出力や標準出力と標準エラー出力の両方をリダイレクトさせたい場合は、下記のように指定します。

指定している数字(ファイルディスクリプタ)には次のような意味があります

  • 1 標準出力 通常のコマンド実行結果
  • 2 標準エラー出力 エラー関係の出力

ちなみに、標準入力のファイルディスクリプタは「0」となります。

  • 0 標準入力 キーボードからの入力

標準出力のファイルディスクリプタの省略について

標準出力のファイルディスクリプタ「1」は省略することができます。

ただし、「&1」を指定する場合には「1」を省略することができません。

出力リダイレクト書式

標準出力・標準エラー出力をリダイレクトさせる際の書式です。

# 標準出力をリダイレクト    
コマンド > ファイル    # 標準出力のファイルディスクリプタ「1」を省略
コマンド 1> ファイル

# 標準出力エラーをリダイレクト
コマンド 2> ファイル

# 標準出力・標準エラー出力両方をリダイレクト
コマンド > ファイル 2>&1
コマンド &> ファイル  (bash拡張)

# 標準出力をファイル1に標準エラー出力をファイル2にリダイレクト
コマンド > ファイル1 2> ファイル2
コマンド 1> ファイル1 2> ファイル2

※「>>」(追記)のパターンもあります。

※「&>」で標準出力と標準エラー出力をリダイレクトさせる方法はbashの拡張機能によるものなので、他のシェルでは動作しないことがあります。

コマンドへのリダイレクト(入力)

コマンドにファイルの中身や文字列をリダイレクトさせる方法としては、以下のようなものがあります。

  • ファイルの内容をコマンドにリダイレクト
  • 文字列をコマンドにリダイレクト
  • 複数行の文字列をコマンドにリダイレクト

入力リダイレクト書式

# ファイルの内容をコマンドへリダイレクト
コマンド < ファイル

# 文字列をコマンドにリダイレクト
# 変数も使用できる
# バッククォート(`コマンド`)で囲んだり、$(コマンド)でコマンドの実行結果も入力できる
コマンド <<< 文字列
コマンド <<< `コマンド`    # コマンドの実行結果を入力したい場合
コマンド <<< $(コマンド)  # コマンドの実行結果を入力したい場合
コマンド <<< 変数          # 変数を入力したい場合

# 複数行の文字列をコマンドにリダイレクト
# ヒアドキュメントともいう
# 変数も使用できる
# バッククォート(`コマンド`)で囲んだり、$(コマンド)でコマンドの実行結果も入力できる
コマンド << 終了文字
文字列
文字列
変数      # 変数を入力したい場合
`コマンド`  # コマンドの実行結果を入力したい場合
$(コマンド)   # コマンドの実行結果を入力したい場合
終了文字

# 行頭のTabを無視したい場合は「<<- 終了文字」を使用
コマンド <<- 終了文字
    文字列
        文字列
終了文字

# 変数の展開やコマンドを実行したくない場合は「<< '終了文字'」や「<< \終了文字」を使用
コマンド << '終了文字'
文字列
`コマンド`    # 文字列として処理される
変数          # 文字列として処理される
終了文字

コマンド << \終了文字
文字列
`コマンド`   # 文字列として処理される
変数         # 文字列として処理される
終了文字

ヒアドキュメントについて

ヒアドキュメントを使うと、複数行の文字列や変数、コマンドの実行結果も入力することができるようになります。

  • 「終了文字」には決まりがないので好きな文字を設定可能
  • 入力完了を示す「終了文字」は単独で入力する必要がある
  • 「<< 終了文字」と「終了文字」の間に入力したい文字列・変数・コマンドを記述

リダイレクト例

標準出力 リダイレクトなし

「echo」コマンドに標準入力で「Hello World」を入力すると、標準出力の出力先である画面に「Hello World」と表示されます。

$ echo "Hello World"
Hello World    # 標準出力

標準出力を「>」(上書き)でファイルにリダイレクト

コマンド > ファイル
コマンド 1> ファイル

標準出力を「>」(上書き)でファイルにリダイレクトしてみます。

$ echo "Hello World" > hello.txt

リダイレクト先のファイルには、標準出力で出力されたHello Worldが書き込まれています。

$ cat hello.txt 
Hello World

このファイルに、再度「>」でリダイレクトを行って、既存のデータを上書きで書き込みすることを確認してみます。

$ echo "Goodbye World" > hello.txt 

もともと記述されていた「Hello World」は消えてしまい、「Goodbye World」だけが記述されているので、既存のデータが削除されたことがわかります。

$ cat hello.txt 
Goodbye World

標準出力を「>>」(追加)でファイルにリダイレクト

標準出力を「>>」(追記)でファイルにリダイレクトしてみます。

$ echo "Hello World" >> hello.txt

追記なので、もともと記述されていたデータのあとにリダイレクトされたデータが追記されていることが確認できます。

$ cat hello.txt 
Goodbye World
Hello World

標準エラー出力をリダイレクト

コマンド 2> ファイル 

標準エラー出力とはエラーに関する出力のことです。

下記の例では「hello.txt」と「world.txt」ファイルを、「cat」コマンドで内容を表示させようとたところ、「world.txt」ファイルが存在していないためエラーが表示されています。

このエラーに関する部分が標準エラー出力にあたります。

$ cat hello.txt world.txt
Goodbye World
Hello World
cat: world.txt: No such file or directory  # 標準エラー出力

標準エラー出力を「error.txt」ファイルにリダイレクトしてみます。

画面上には標準出力だけが表示されています。

$ cat hello.txt world.txt 2> error.txt
Goodbye World
Hello World

標準エラー出力については、ファイルの方にリダイレクトされていることが確認できます。

$cat error.txt 
cat: world.txt: No such file or directory

標準出力と標準エラー出力をリダイレクト

コマンド > ファイル 2>&1
コマンド &> ファイル  

標準出力と標準エラー出力の両方をリダイレクトさせてみます。

コマンド > ファイル 2>&1

標準出力と標準エラー出力の療法を「error.txt」ファイルにリダイレクトさせます。

$ cat hello.txt world.txt > error.txt 2>&1

「error.txt」の内容を確認すると、標準出力と標準エラー出力の両方がリダイレクトされていることが確認できました。

$ cat error.txt 
Goodbye World
Hello World
cat: world.txt: No such file or directory

コマンド &> ファイル (bash拡張)

こちらの書式「&>」はbashの拡張機能なので、bash以外では動作しないかもしれません。

$ cat hello.txt world.txt &> error.txt

こちらの場合も、標準出力と標準エラー出力の両方がリダイレクトされていることが確認できました。

$ cat error.txt 
Goodbye World
Hello World
cat: world.txt: No such file or directory

標準出力と標準エラー出力を別々のファイルにリダイレクト

コマンド > ファイル1 2> ファイル2
コマンド 1> ファイル1 2> ファイル2

標準出力を「helloworld.txt」へ、標準エラー出力を「error.txt」にと、それぞれ別のファイルにリダイレクトさせてみます。

$ cat hello.txt world.txt > helloworld.txt 2> error.txt

標準出力である「hello.txt」の内容が「helloworld.txt」リダイレクトされていることが確認できます。

$ cat helloworld.txt 
Goodbye World
Hello World

標準エラー出力についても、「error.txt」にリダイレクトされていることが確認できました。

$ cat error.txt 
cat: world.txt: No such file or directory

ファイルの内容をコマンドへリダイレクト

コマンド < ファイル

わざわざこんな使い方しないと思いますが、動作例としてテキストが記述されているファイル「helloworld.txt」を「cat」コマンドにリダイレクトします。

$ cat < helloworld.txt  
Goodbye World
Hello World

ファイルに記述されている内容が「cat」で表示されました。

文字列をコマンドにリダイレクト

「<<<」を使用すると、文字列・変数・コマンド実行結果等をコマンドにリダイレクトさせることができます。

コマンド <<< 文字列
コマンド <<< 変数
コマンド <<< `コマンド`
コマンド <<< $(コマンド)

文字列をリダイレクト

「<<<」を使用して「helloworld.txt」をリダイレクトさせると、文字列として「cat」コマンドに認識されるため「helloworld.txt」がそのまま表示されます。

$ cat <<< helloworld.txt 
helloworld.txt

変数をリダイレクト

環境変数である「$USER」を「cat」コマンドにリダイレクトすると、格納されているユーザ名が表示されます。

$ cat <<< $USER
tamohiko

コマンド実行結果をリダイレクト

「`コマンド`」や「$(コマンド)」といった形でコマンドの実行結果もリダイレクトさせることができます。

$ cat <<< `date "+%Y-%m-%d %H:%M:%S"`
2022-02-24 10:46:27
$ cat <<< $(date "+%Y-%m-%d %H:%M:%S")
2022-02-24 10:46:56

複数行の文字列をコマンドにリダイレクト(ヒアドキュメント)

コマンド << 終了文字
文字列
文字列
変数  # 変数も展開できる
`コマンド`  # コマンドの実行結果を入力したい場合
$(コマンド)   # コマンドの実行結果を入力したい場合
終了文字

# Tabを無視したい場合は「<<- 終了文字」を使用
コマンド <<- 終了文字
    文字列
        文字列
終了文字

# 変数の展開やコマンドを実行したくない場合は「<< '終了文字'」や「<< \終了文字」を使用
コマンド << '終了文字'
文字列
`コマンド`    # 文字列として処理される
変数          # 文字列として処理される
終了文字

コマンド << \終了文字
文字列
`コマンド`    # 文字列として処理される
変数          # 文字列として処理される
終了文字

終了文字について

終了文字は決まりがないので、自分で好きなように決めることができます。

ここでは「EOT」を終了文字としていますが、「EOF」でも「EOD」でも(それ以外でも可)お好きな文字列を終了文字として指定してすることができます。

ちなみに、「EOT」は「End Of Text」の頭文字をとったものらしいです。

複数行の文字列のリダイレクト

ヒアドキュメントでは、複数行の文字列以外にもコマンドの実行結果や、変数をリダイレクトすることができます。

$ cat << EOT
> Hello
> World !!
> EOT
Hello
World !!

コマンドの実行結果や変数も展開できます。

$ cat << EOT 
> `date "+%Y-%m-%d %H:%M:%S"`
> $(date "+%Y-%m-%d %H:%M:%S")
> $USER
> EOT
2022-02-25 17:24:52
2022-02-25 17:24:52
tamohiko

行頭のTabを無視したい場合

「<<- 終了文字」を使用することで、行頭のTabを無視させることができます。

動作確認用として、下記のようなシェルスクリプトを作成しました。

空白部分は「Tab」となっています。

$ cat heardoc.sh 
#!/bin/bash
echo "### << EOT ###"
cat << EOT
	Hello
		World !!
EOT
echo "### <<- EOT ###"
cat <<- EOT
	Hello
		World !!
Hello	World !!
EOT

「<<- EOT」を使用している方は、行頭の「Tab」が無視されて「cat」コマンドにリダイレクトされていることがわかります。

行の途中に含まれている「Tab」はそのまま「Tab」として処理されていることも確認できます。

$ sh heardoc.sh 
### << EOT ###
	Hello
		World !!
### <<- EOT ###
Hello
World !!
Hello	World !!

変数展開やコマンドを実行させたくない場合

終了文字の前に「\」バックスラッシュを入れたり、シングルクォーテーションで終了文字を括ることで、変数やコマンドはそのまま文字列として処理されます。

「\終了文字」の場合
$ cat << \EOT
> `date "+%Y-%m-%d %H:%M:%S"`
> $(date "+%Y-%m-%d %H:%M:%S")
> $USER
> EOT
`date "+%Y-%m-%d %H:%M:%S"`
$(date "+%Y-%m-%d %H:%M:%S")
$USER
「'終了文字'」の場合
$ cat << 'EOT'
> `date "+%Y-%m-%d %H:%M:%S"`
> $(date "+%Y-%m-%d %H:%M:%S")
> $USER
> EOT
`date "+%Y-%m-%d %H:%M:%S"`
$(date "+%Y-%m-%d %H:%M:%S")
$USER

最後の終了文字は行の頭に記述する必要がある

入力完了の合図となる終了文字は、行頭から終了文字だけを記述する必要があります。

行頭に空白がある場合

行頭に空白があるので、終了文字と認識されません。

$ cat << EOT                         
> Hello
> World !!
>  EOT    # 先頭に空白がある
> EOT
Hello
World !!
 EOT  # 終了文字として認識されず文字列として処理される
入力文字列の後に終了文字を記述

文字列の後に終了文字を記述しても終了文字として認識されません。

$ cat << EOT
> Hello 
> World !!  EOT  # 文字列の途中にEOTを記述
> EOT
Hello
World !!  EOT   # 終了文字としては認識されずに処理される
終了文字の後ろに文字を記述

終了文字の後ろに文字列が記述されると、終了文字として認識されません。

$ cat << EOT
> Hello
> World !! 
> EOT text  # 終了文字のあとに文字列を記述
> EOT
Hello
World !!
EOT text  # 終了文字としては認識されずに処理される

シェアする