Linuxコマンド - awk
概要
awk
コマンドとは、入力として受け取った文字列に対して、フィールド区切り文字やレコード区切り文字を指定して、
列に対する処理を行うためのコマンドである。
awkのインストール
パッケージ管理システムからインストール
多くのLinuxディストリビューションでは、パッケージ管理システムからgawkをインストールすることができる。
sudo zypper install gawk
ソースコードからインストール
もし、別途インストールする必要がある場合、ソースコードからgawkをインストールする。
gawkのビルドに必要なライブラリをインストールする。
sudo zypper install mpfr-devel readline-devel gettext-runtime gettext-tools intltool libsigsegv-devel
GNUソフトウェアの公式Webサイトにアクセスして、ソースコードをダウンロードする。
ダウンロードしたファイルを解凍する。
tar xf gawk-<バージョン>.tar.xz cd gawk-<バージョン>
gawkをビルドおよびインストールする。
mkdir build && cd build ../configure --prefix=<gawkのインストールディレクトリ> make -j $(nproc) make install
gawkの実行に必要な依存関係のライブラリをインストールする。
sudo zypper install libsigsegv2
~/.profileファイル等に、環境変数PATHを追記する。
vi ~/.profile
# ~/.profileファイル export PATH="/<gawkのインストールディレクトリ>/bin:$PATH" export LD_LIBRARY_PATH="/<gawkのインストールディレクトリ>/lib64:/<gawkのインストールディレクトリ>/lib:$LD_LIBRARY_PATH"
awkコマンドの基本書式
awk
コマンドの基本書式を以下に記載する。
awk -F'[フィールド区切り文字(複数可能)]' -v '変数=xx' '{awkコマンド}' file
フィールドの出力
標準出力を行うawk
コマンドのprint
を使用して、awk
コマンドで指定したフィールドを取得する。
-F'[フィールド区切り文字]'
オプションを指定しない場合、区切り文字にはタブまたは半角スペースが選択される。
1フィールド目を出力 : print $1
# 実行 echo 1 2 3 4 | awk '{print $1}' # 出力 1
2フィールド目の出力 : print $2
# 実行 echo 1 2 3 4 | awk '{print $2}' # 出力 2
全ての文字列の出力 : print $0 または print
# 実行 echo 1 2 3 4 | awk '{print $0}' # 出力 1 2 3 4
# 実行 echo 1 2 3 4 | awk '{print}' # 出力 1 2 3 4
フィールド区切り文字の指定
フィールド区切り文字として、":"を指定する。
# 実行 echo 1:2:3:4 | awk -F'[:]' '{print $1}' # 出力 1
また、フィールド区切り文字は複数指定できる。
以下の例では、フィールド区切り文字として、":"と"/"を指定している。
並べて記述することで、":"と"/"がフィールド区切り文字として扱われる。
# 実行 echo 1:2/3:4 | awk -F'[:/]' '{print $3}' # 出力 3
複数フィールドの出力は、半角スペースで区切られる。(OFSを指定していないため)
OFSについては、後述のセクションを参照すること。
# 実行 echo 1:2/3:4 | awk -F'[:/]' '{print $1,$2}' # 出力 1 2
OFS
OFS
(Output Field Separator)とは、awkコマンドの組み込み変数であり、出力のフィールド区切り文字を指定する。
-v
オプションは、変数(variable)を指定するという意味のオプションである。
-v '変数=xx'
以下の例では、OFSに半角スペースを指定して、フィールドの出力を#で区切る。
# 実行 echo 1:2/3:4 | awk -F'[:/]' -v 'OFS= ' '{print $1,$3}' # 出力 1 3
RS
RS
(Record Separator)とは、awkコマンドの組み込み変数であり、入力のレコード区切り文字を指定する。
以下の例では、/を区切り文字に指定して、1:2と3:4に分けている。
/をレコード区切り文字にして、各レコードから1フィールド目を取得している。
出力は、改行で区切って出力される。(ORSが指定されていないため)
# 実行 echo 1:2/3:4 | awk -F'[:]' -v 'RS=/' '{print $1}' # 出力 1 3
# 実行 echo 1:2/3:4 | awk -F'[:]' -v 'RS=/' '{print $1,$2}' # 出力 1 2 3 4
フィールド区切り文字とレコード区切り文字で同じ文字がある場合、レコード区切り文字が優先される。
# 実行 echo 1:2/3:4 | awk -F'[:/]' -v 'RS=/' '{print $1,$2}' # 出力 1 2 3 4
ORS
ORS
(Output Record Separator)とは、awkコマンドの組み込み変数であり、出力のレコード区切り文字を指定する。
以下の例では、"This is ORS"を指定して、レコードの出力を区切っている。
# 実行 echo 1:2/3:4 | awk -F'[:/]' -v 'RS=/' -v 'ORS=This is ORS' '{print $1,$2}' # 出力 1 2This is ORS3 4
OFSとORSの明示
以下の例では、OFSは空白4つ、ORSは改行2つにしている。
また、\nは改行を示す。
# 実行 echo 1:2/3:4 | awk -F'[:/]' -v 'OFS= ' -v 'RS=/' -v 'ORS=\n\n' '{print $1,$2}' # 出力 1 2
3 4
最終フィールドの取得 : $NF
最終フィールドを取得するとして、$NFが用意されている。
# 実行 echo 1:2/3:4 | awk -F'[:/]' '{print $NF}' # 出力 4
# 実行 echo 1:2/3:4 | awk -F'[:/]' '{print $NF-1}' # 出力 3
printf
printの他に、printfも使用できる。
# 実行 echo 1:2/3:4 | awk -F'[:/]' '{printf "%s\n%s\n",$NF,$NF-1}' # 出力 4 3
awkを使用したフィルタリング
空白で区切られた特定のフィールドを切り出す
awk
の組み込み変数$x
には、xフィールド目に存在する文字列が設定されている。
これを、awk
のprint
文で出力することにより、特定のフィールドのみを切り出すことができる。
cut
コマンドでも空白区切りのフィールドを切り出すことが可能だが、特に、フィールド間の空白数が一定でない場合はawk
コマンドを使用する。
一定の空白数の有無に関わらず、空白区切りのフィールドを切り出すには、awk
コマンドを使用した方がよい。
awk '{ print $フィールド番号 }' # awkコマンドの組み込み変数で対象フィールドのみを出力する
以下の例では、特定のフィールドを切り出している。
cat test.txt 111 ABC abc 222 DEF def 333 GHI ghi 444 JKL jkl 555 MNO mno 666 PQR pqr 777 STU stu 888 VWX vwx 999 YZ yz
1フィールド目を切り出す。
awk '{ print $1 }' test.txt 111 222 333 444 555 666 777 888 999
2フィールド目を切り出す。
awk '{ print $2 }' test.txt ABC DEF GHI JKL MNO PQR STU VWX YZ
3フィールド目を切り出す。
awk '{ print $3 }' awktest.txt abc def ghi jkl mno pqr stu vwx yz
対象となる行を特定してフィールドを切り出す。
行番号を指定することで、処理対象となる範囲を限定することができる。
また、行番号指定の場合は、==
以外にも、<
、>
、<=
、>=
、!=
が使用できる。
さらに、||
(OR条件)や&&
(AND条件)で複数の条件を指定することもできる。
NR
は行番号を表すawkコマンドの組み込み変数である。
awk '(NR == 行番号){ print $フィールド番号 }' # awkコマンドに処理対象とする行番号を指定する
1行目のみを処理対象とする。
awk '(NR == 1){ print $1 }' test.txt 111
1行目および9行目を処理対象とする。
awk '(NR == 1 || NR == 9){ print $1 }' test.txt 111 999
5行目を超えて8行目以下、つまり、6行目から8行目までの行を処理対象とする。
awk '(NR > 5 && NR <= 8){ print $1 }' test.txt 666 777 888
空白で区切られたフィールドの順番を入れ替える
"hoge fuga foo bar"のように空白で区切られた各フィールドを、"bar hoge bar foo"のように順番を入れ替えて出力するには、awk
コマンドを使用する。
awk
コマンドにおいて、$xはx番目のフィールドを意味する。
つまり、フィールドの順番を入れ替えるには、出力したい順番で$xを指定する。
例えば、3つのフィールドの順番を逆にする場合は、$3" "$2" "$1
と指定する。
" "
は、フィールド間のスペースを意味するため、これを指定せずに実行すると、各フィールドが結合した状態で出力されてしまう。
awk '{ print $フィールド番号" "$フィールド番号" "..." "$フィールド番号 }' # awkコマンドで各フィールドの番号を出力したい順に指定する
cat shuffle.txt 111 ABC abc 222 DEF def 333 GHI ghi 444 JKL jkl 555 MNO mno
以下の例では、空白スペース" "を指定していないため、全て結合された状態で出力されている。
awk '{ print $3 $1 $2 }' shuffle.txt abc111ABC def222DEF ghi333GHI jkl444JKL mno555MNO
以下の例では、$xの間に" "を指定しているため、フィールド間がスペースで区切られている。
awk '{ print $3" "$1" "$2 }' shuffle.txt abc 111 ABC def 222 DEF ghi 333 GHI jkl 444 JKL mno 555 MNO
以下の例では、同じフィールドを2回出力している。
awk '{ print $3" "$1" "$1" "$2 }' shuffle.txt abc 111 111 ABC def 222 222 DEF ghi 333 333 GHI jkl 444 444 JKL mno 555 555 MNO
シェルスクリプトに組み込んで使用する場合は、以下のように、パイプでデータを引き渡して実行することが多い。
以下の例でのように、処理対象データから予め不要な部分を取り除いた上でawkに引き渡すことで、awkを簡素に記述することができる。
head -n 3 shuffle.txt | awk '{ print $2 }' ABC DEF GHI
※備考
awkはコマンドではなく、インタプリタでありシェルスクリプトとは異なるスクリプト言語である。
元々、テキスト処理のために開発されたスクリプト言語であるため、シェルスクリプトよりも高速にテキスト処理を行うことができる。
awkはシェルスクリプトに組み込むことが容易であるため、awkのみで使用するよりもシェルスクリプト内でフィルタとして使用されることが多い。
シェルスクリプトで行数の多いテキストファイルを処理する場合、一部にawkを使用することで高速なプログラムを記述することができる。
テキストファイルの処理にはPerl等を使用した方が便利な場合もあるが、Perl等が使用できない環境ではawkを使用する方がよい。