以下のシェルスクリプトの動作を理解しようとしています。引数なしのexecは現在のシェルの出力をリダイレクトしますが、以下のコマンドが何をするのか理解できません。
exec 1>/var/opt/log/my_logs/MYPROG_`date '+%Y%m%d_%H%M%S'`.log 2>&1
実際には、次の4つの重要な情報が発生しています。
exec
組み込み は、コマンドラインセッションのすべての出力をファイルにリダイレクトするために使用されます
1><FILENAME>
は、シェルにリダイレクトするように指示します stdout
標準ストリーム 、つまり、コマンドの通常の非エラー出力は<FILENAME>
に送られます。 >
は、<FILENAME>
が存在しない場合は作成され、<FILENAME>
が既に存在する場合は切り捨てられます。
リダイレクトされたファイル名は、date '+%Y%m%d_%H%M%S'
コマンドを使用して追加されたバックティックを介して作成されます。バックティックは Command Substitution の形式であり、機能的には$(date '+%Y%m%d_%H%M%S')
形式と同等です。最近では$(...)
が読みやすく、この形式は簡単に入れ子にできる(つまり、複数のレベルを持つ) )。したがって、指定された形式'+%Y%m%d_%H%M%S'
でdate
を出力すると、タイムスタンプが付けられたファイル名が作成されます。コマンドが2018年7月4日4時20分20秒に実行された場合、出力は/var/opt/log/my_logs/MYPROG_20180704_042020.log
になります。
2>&1
はstderr
ストリームもそのファイルにリダイレクトします。これは標準のPOSIX準拠です(つまり、bash
以外のBourneのようなシェルはそれを理解します)。これは 機能的に&>
と同等 bash固有の構文です。シェルで指定されたリダイレクトの順序は重要であるため、1>
リダイレクトの後にこれが表示されるのはなぜですか。
結論として、このコマンド自体からの出力はないはずです。連続するすべてのコマンドの2つの出力ストリームのみを再配線して、指定したファイルに移動する必要があります。
興味深いことに、このコマンドで私のbash 4.4
はすべてをファイルに出力し、プロンプトと入力したものをすべて含みます(したがって、ここで盲目的にecho hello world
と入力し、その後Ctrl + Dを押して終了しなければなりません):
$ bash --posix
bash-4.4$ exec 1>./mylog_`date '+%Y%m%d_%H%M%S'`.log 2>&1
$ cat ./mylog_20180424_010800.log
bash-4.4$ echo hello world
hello world
bash-4.4$ exit
少しずつそのことを行うと、bash
がstderr
ストリームにPromptを出力し、驚くことに私が入力したものと一緒になっていることがわかります。
bash-4.4$ exec 1> ./mylog.txt
bash-4.4$ echo Hello World
bash-4.4$ cat ./mylog.txt
cat: ./mylog.txt: input file is output file
bash-4.4$ exec 2>&1
ksh
の場合と同じことが起こりますが、入力されている内容を確認できます。プロンプトのみがファイルに保存されます。つまり、stdinはリダイレクトされません。
bash-4.4$ ksh
$ exec 1>./mylog 2>&1
echo hello askubuntu
bash-4.4$ cat ./mylog
$ hello askubuntu
$
bash-4.4$
したがって、ここでは、シェルがプロンプトPS1
を標準ストリームの1つにも出力することを選択できることがわかります。これにより、ファイルに含まれます。