awk(gawk)でファイルを読み込めない場合、致命的なエラーとして扱われ、awkのスクリプトの処理が即時に終了してしまいます。awkで複数のファイルを処理したいときに、途中でawkの処理が終了すると困る場合があります。そのような時はBEGINFILEと変数ERRNOを用いると、ファイルが読み込めない場合、そのファイルを読み飛ばすような処理を行うことができます。
BEGINFILEについて
awkの処理の流れは、処理の開始時にBEGINでの処理を行い、その後にファイルを読み込むごとに、BEGINFILEでの処理->特別なパターン以外のawkの処理->ENDFILEでの処理 のように繰り返し処理を行い、最後にENDでの処理を行って終了します。
BEGINFILEはファイルを読み込むごとに、それぞれ1回だけ最初に処理が実行されます。
変数ERRNO
変数ERRNOはawkの組み込み変数でgetlineやcloseの操作を行った際、システムエラーが発生したときにエラーの内容が入る変数です。
さらにファイルを読み込む前に値が消去されるので、BEGINFILEで利用するとファイルを読み込んだときにエラーが起きたかどうかを確認できます。
ファイルが読み込めない場合にそのファイルを飛ばす
awkで複数のファイルを処理したいときにファイルを読み込むことができない場合、致命的なエラーが起きて、その読み込めないファイルで処理が途中で停止するときがあります。
エラーが起きた場合の例
1 2 3 |
$ awk '{print NR,$0}' file* 1 file1 content awk: cmd. line:1: fatal: cannot open file `file2.txt' for reading (Permission denied) |
そのような場合は、BEGINFILEと変数ERRNOを組み合わせると以下のようにファイルが読み込めないときにそのファイルを飛ばすことができます。awkで行う処理としてはawkで読み込んだ行数とファイルの内容を表示しています。
file1.txtとfile2.txtとfile3.txtの権限とその内容
1 2 3 4 5 6 7 8 9 10 |
$ ls -l file* -rw-rw-r-- 1 ubuntu ubuntu 15 12月 7 19:08 file1.txt -rw------- 1 root root 14 12月 7 19:08 file2.txt -rw-rw-r-- 1 ubuntu ubuntu 14 12月 7 19:08 file3.txt $ cat file1.txt file1 content $ sudo cat file2.txt file2 content $ cat file3.txt file3 content |
script.awk
1 2 3 4 5 6 7 8 9 |
BEGINFILE { if(ERRNO) { nextfile } } { print NR,$0 } |
コマンド例と実行結果
1 2 3 |
$ awk -f script.awk file* 1 file1 content 2 file3 content |
また、awkのif文の条件は0とヌル文字列以外は真になります。
ERRNOの値はファイルが読み込まれる前に消去されます。上の例ではファイルが読み込めない場合はERRNOに何らかの値が入るため、nextfile文で次のファイルに処理が移行するような処理になっています。
このときのファイルが読み込めない場合のERRNOの値は以下のようになっています。
1 2 |
$ awk 'BEGINFILE{print ERRNO; exit}' file2.txt Permission denied |
また、上のファイルの内容を表示する処理のワンライナーの形式として、以下のように記述できます。
1 2 3 |
$ awk 'BEGINFILE{if(ERRNO)nextfile} {print NR,$0}' file* 1 file1 content 2 file3 content |