環境
ターミナル上の作業ログを取りたい場合
script
コマンドを使うとターミナル上の操作と出力を全てファイルに記録できる
$ script Script started, output file is typescript $ echo hoge hoge $ ls hoge ls: cannot access 'hoge': No such file or directory $ exit
- 下記のように入力と標準出力と標準エラー出力が全て記録されている
// typescript Script started on Sun Dec 2 19:15:10 2018 bash-4.4$ echo hoge hoge bash-4.4$ ls hoge ls: cannot access 'hoge': No such file or directory bash-4.4$ exit exit Script done on Sun Dec 2 19:15:45 2018
実行するシェルスクリプトのログを画面に表示しつつファイル出力したい場合
script
は別プロセスを起動するのでうまく使えない.sh
ファイル実行中の標準出力と標準エラー出力をログとしてファイルへ出力しつつターミナルの画面にも出力する- 下記のコードはこちらの記事(bashのプロセス置換機能を活用して、シェル作業やスクリプト書きを効率化する - 双六工場日誌)を参考にした1
exec 1> >(tee -a stdout.log) exec 2> >(tee -a stderr.log) # 処理 echo hoge
- なる...ほど?
- シェルスクリプトに慣れ親しんでいないと分かりにくい(少なくとも自分は理解できなかった)
- 分解して考えてみる
リダイレクト
- 始めにリダイレクトの概念を知っている必要がある
リダイレクトは標準入出力の入力元、出力先を置き換える機能のこと
[三宅 英明 (2017) . 新しいシェルプログラミングの教科書 SBクリエイティブ P115より引用]
- 例えば
echo hoge 1> hoge.log
は標準出力をhoge.log
にリダイレクトする - 1はファイルディスクリプタの番号
- 0:標準入力、1:標準出力、2:標準エラー出力
1>
を省略すると>
になるのでecho hoge > hoge.log
でも良い
exec
コマンド
- 続いて
exec
execに指定したコマンドを実行する。このコマンドを実行する際に,新しいプロセスを作成せずに,現在のジョブと置き換えて実行される。...また,何もコマンドを指定せずにリダイレクトを利用すると,現在のシェルのリダイレクトを切り替えられる。
【 exec 】 現行のジョブに置き換えてコマンドを続行する | 日経 xTECH(クロステック)より引用
- ここではコマンドを指定していないのでシェルのリダイレクトを切り替えている
プロセス置換
<(command)
と>(command)
の2つがある
<(command)
<(command)
は、プロセス置換によって割り当てられたファイルにcommand
の標準出力を出力- シェル芸でも時々使う
$ echo <(echo test) /dev/fd/63 $ cat <(echo test) test
>(command)
>(command)
は、プロセス置換によって割り当てられたファイルの内容を標準入力としてcommand
を実行exec
と組み合わせることが多い模様- 今回はシェルの出力が、一時的に割り当てられたファイルへリダイレクトされ、それを標準入力としてコマンドが実行される
tee
コマンド
- 標準出力しつつファイルにも出力する
- 処理の流れがT字型のイメージ
-a
はファイルに追記のオプション
$ echo hoge | tee hoge.log hoge $ cat hoge.log hoge
これらを踏まえて
- もう1度見てみる
exec 1> >(tee -a stdout.log) exec 2> >(tee -a stderr.log)
- 現在のシェルの標準出力と標準エラー出力をそれぞれ
tee
の標準入力にすることで画面に出力しつつファイルへの記録を実現している - 処理の意味が理解できた!(と思う)
最後に
- シェルに詳しくないので他にも出力の方法はあるかも
- あとこの記事はチームスピリット Advent Calendar 2018 - Adventarの3日目の記事ということになってます
- 今年は参加率高い!
-
元記事の
exec 2> >(tee -a stderr.log >&2)
の>&2
はどうして必要なのかよく分からなかった。知っている方いたら教えてください↩