よくawkで処理中にOSのコマンドを実行させる事があるので、備忘で残しておく。
1.ただコマンドを実行させる
ただOSのコマンドを実行するだけで良いのであれば、system()を使用すればいい。
awk '{system("OSのコマンド")}'
blacknon@BS-PUB-UBUNTU-01:~$ cat test2.txt a01 15652 a02 13411 a03 2597 a04 8083 a05 11068 a06 17737 a07 32745 a08 22546 a09 32608 a10 32074 a11 17574 a12 8745 a13 2201 a14 7521 a15 9968 a16 12236 a17 19420 a18 30606 a19 21637 a20 16093 blacknon@BS-PUB-UBUNTU-01:~$ cat test2.txt | awk '{system("echo "$2"|cut -c 1-3")}' 156 134 259 808 110 177 327 225 326 320 175 874 220 752 996 122 194 306 216 160
ただ、このやり方だと残念ながら実行結果をawk内の変数に代入できず(exit codeが代入されてしまう)、かつprintでも扱えない(指定するとexit codeがprintされてしまう)。
blacknon@BS-PUB-UBUNTU-01:~$ cat test2.txt | head | awk '{print $1,system("echo "$2"|cut -c 1-3")}' 156 a01 0 134 a02 0 259 a03 0 808 a04 0 110 a05 0 177 a06 0 327 a07 0 225 a08 0 326 a09 0 320 a10 0
また、こちらを見ると入出力streamを開いてしまうので、実行時に明示的にcloseしてやらないとファイルディスクリプタを消費してしまう様子。
2.コマンドの実行結果をawk内で変数に代入する
awkからOSのコマンドを実行し、その結果を変数に代入する場合、以下のようにgetlineを利用する。
awk '{"OSのコマンド" | getline var}' # 変数varにOSコマンドの実行結果が代入される
blacknon@BS-PUB-UBUNTU-01:~$ cat test2.txt | head | awk '{"echo "$2"|cut -c 1-3" | getline t;print $1,t}' a01 156 a02 134 a03 259 a04 808 a05 110 a06 177 a07 327 a08 225 a09 326 a10 320
なお、OSコマンドの実行結果が複数行になる場合、変数に代入されるのは最初の1行だけになるようなので、そこは注意が必要になるようだ。
複数行が必要になる場合、OSコマンドの実行結果は一行にし、あとでawk内で分解して扱うのが良さそうだ。
blacknon@BS-PUB-UBUNTU-01:~$ cat test2.txt | head | awk '{"echo "$2"|cut -c 1-3|grep -o ." | getline t;print $1,t,length(t)}' a01 1 1 a02 1 1 a03 2 1 a04 8 1 a05 1 1 a06 1 1 a07 3 1 a08 2 1 a09 3 1 a10 3 1
