Wet系バイオインフォマティシャンの災難

機械に弱いバイオ研究者に降りかかる災難を綴っていきます。 Twitter: @1wantphd

シェルスクリプトに出てくる「2>&1」ってなんですか?【エラーログの保存に使えます】

シェルスクリプトを書くために勉強をしていると

時々行末に「2>&1」という記号を見かけると思います。

プログラミング初心者には意味不明なこの呪文について解説をしたいと思います。

この呪文はファイルディスクリプタと呼ばれる番号"1, 2"と

リダイレクト">"から成り立っているのでこの2つについてをまず解説します。

 

コマンドによる出力には”標準出力”と”標準エラー出力”の2種類がある 

コマンドechoを例に説明します。

まず、echoで”Hello”と表示させてみましょう。

$echo "Hello"
Hello

"Hello"と問題なく出力されます。

これが標準出力です。

 

次に存在しないコマンドaaaを行ってみると

$aaa "Hello" 
-bash: aaa: command not found

"aaaというコマンドはありません"というエラーメッセージが出ます。

これが標準エラー出力です。

 

上記の "標準出力"と "標準エラー出力"にはそれぞれ"1" "2"という番号が与えられており、この番号をファイルディスクリプタと呼びます。

この番号と">(リダイレクト)"を使うことでそれぞれの出力を呼び出すことができます。

リダイレクトとはコマンドの出力先を変更する記号で

> (file名).txtとすることで指定したファイルにコマンドの結果を出力することができます。

 

それでは、echoの標準出力と標準エラー出力を2つのファイルにリダイレクトしてみましょう。

$ echo "Hello" 1>result.txt 2>error.txt
$ cat result.txt
Hello
$ cat error.txt
$

echo "Hello"によって出力される"Hello"はresult.txtにリダイレクトされたため、

これまでと異なりecho後、ターミナル上には表示されません。

その代わりにcatでresult.txtファイル内を開くと

"Hello" と書き込まれていることがわかります。

echo "Hello"ではエラーが出ませんので

error.txtには何も書き込まれていません。

 

次に、エラーが出るaaaというコマンド(?)を使ってみましょう。

$aaa "Hello" 1>result.txt 2>error.txt
$cat error.txt 
-bash: aaa: command not found
$cat result.txt
$

aaa "Hello!"で出力されるエラーメッセージは

error.txtに書き込まれていました。

aaaは存在しないコマンドでエラー以外に出力される結果はありませんので、

result.txtファイルには何も書き込まれていません。

  

2>&1は標準エラー出力を標準出力と一緒に出力させる

上記の内容から"2>&1"が標準エラー出力(2)を標準出力(1)にリダイレクトさせているということはなんとなくわかると思います。

では&とは何でしょうか。

&なしで以下のコマンドを実行してみると

$echo "Hello" 2>1
"Hello"

とくに何も起こらないように見えますが

カレントディレクトリに[1]というファイルが新たに出現しています。

しかし、このファイルには何も書かれていません。

$cat 1
$

これはecho "Hello"標準エラー出力(2)を[1]というファイルにリダイレクトしたために生まれたファイルであり、エラーメッセージが出ないのでファイルは空です。

そのため、エラーメッセージの出るaaaを使うと

$aaa "Hello!" 2>1
$cat 1
-bash: aaa: command not found

[1]というファイルにはエラーメッセージが書き込まれました。

 

では&とは一体なんなのでしょうか。

これはマージを意味しており、

「標準出力と標準エラー出力をまとめて出力する」を意味しています。

そのため、 2>&1を使えば標準出力と標準エラー出力をまとめてresult.txtファイルに書き込むことができます。

$echo "Hello"  >result.txt 2>&1
$cat result.txt
Hello 
$aaa "Hello" >result.txt 2>&1
$cat result.txt
-bash: aaa: command not found

echoの標準出力もaaa標準エラー出力もresult.txt内に保存することができました。

これをシェルスクリプト内で使えばエラーメッセージが出た場合には指定のファイルにログを保存させることができますのでデバックする際などに役立てることができます。

 

 

 

おまけ・リダイレクトの種類

リダイレクトはシェルスクリプトを書く際に大事な手法なので

使い方をまとめた表をhttps://eng-entrance.com/linux-redirect様より転載させていただきました。

 この機会に覚えておきたいですね。

コマンド > ファイル コマンド結果をファイルへ書き込む
コマンド < ファイル ファイルの中身をコマンドの標準入力へ
コマンド >> ファイル コマンドの出力結果をファイルへ追記
コマンド 2> ファイル エラー出力をファイルへ書き込む
コマンド 2>> ファイル ファイルにエラー出力を追記
コマンド > ファイル 2>&1 ファイルに標準出力と標準エラー出力を書き込む
コマンド >> ファイル 2>&1 ファイルに標準出力と標準エラー出力を追記
コマンド << 終了文字 終了文字が現れるまで標準入力へ送る
コマンド &> ファイル 標準出力と標準エラー出力を同じファイルに書き込む
コマンド > /dev/null 2>&1 表示をしない。(表示をゴミ箱へ)

https://eng-entrance.com/linux-redirectより引用

 

参考

https://qiita.com/ritukiii/items/b3d91e97b71ecd41d4ea

https://qiita.com/tsubasaogawa/items/9495ad6e903998c4d1ac

https://qiita.com/toshihirock/items/78286fccf07dbe6df38f