Unix流 コマンドとパイプ
2023年11月、シェルとAWKを使ってちょっとしたプログラムを書いています。
Unix流考え方に習い、小さなプログラムをパイプで組み合わせて目的の機能を実現しています。小さなプログラムは、単機能となり理解しやすくなります。
この図は、cmd1の出力をパイプを通してcmd2に入力します。
このパイプの間にteeコマンドを挟むと、入力を出力のパイプに流すと同時に入力データをログファイルに出力することができます。こうすれば、パイプの中身を確認できます。
シェル変数をAWKに渡したい!
シェルとAWKを組み合わせてプログラミングしているとシェル変数の値をAWKに引き渡したいことが多々あります。
昔、技術者現役の時代にUnixで仕事していたときによくやっていました。しかし、久しぶりにAWKを使っていると、そのやり方を思い出せなかったので調べました。せっかくなので、今後のためにここにメモしておきます。
例えば、下記のような処理をしたいとします。
ファイルにある文書が入っており、日付の部分を{DATE}で記述しています。
シェル変数に日付を格納して、AWKを起動するときにこのシェル変数の値を引き渡して、AWKで文字列{DATE}をシェル変数の値に置換するとします。
入力データを下記に示します。
$ cat test.txt
-----------------------------------------------------
新書発売のお知らせ {DATE}
新書「超マシン復活 #5 DEC TOPS-20 レトロなOSの散歩道」
をアマゾンから発売しました。
-----------------------------------------------------
$
シェル変数にdateコマンドで取得した日付を格納します。そのシェル変数をAWKに渡すには、3つの方法があります。
- -vオプションでAWK変数を定義して渡す方法
- AWKでシェル変数の値を覗く方法
- AWKの入力ファイル先頭にシェル変数の値を格納する方法
【方法-1】-vオプションでAWK変数を定義して渡す方法
この【方法-1】は、AWKの-vオプションでAWK変数を定義します。
そして、AWK変数「vdate」にシェル変数「WHEN」の値を渡します。
#!/bin/sh
#
WHEN=`date "+%Y-%m-%d"`
#
cat test.txt |
awk -v vdate="${WHEN}" '
{
gsub(/{DATE}/ ,vdate);
print $0;
}
'
実行してみます。
$ ./test1.sh
-----------------------------------------------------
新書発売のお知らせ 2023-11-14
新書「超マシン復活 #5 DEC TOPS-20 レトロなOSの散歩道」
をアマゾンから発売しました。
-----------------------------------------------------
$
【方法-2】AWKでシェル変数の値を覗く方法
この【方法-2】は、AWKでシェル変数の値を覗きます。
AWKのBEGIN処理で、AWK変数「vdate」にシェル変数「WHEN」の値を覗いて渡します。
#!/bin/sh
#
WHEN=`date "+%Y-%m-%d"`
#
cat test.txt |
awk ' BEGIN { vdate="'${WHEN}'"; }
{
gsub(/{DATE}/ ,vdate);
print $0;
}
'
最初は、AWKの中からシェル変数の値が覗けることが不思議でした。
私の理解が正しいか分かりませんが、シングルクォーテーションで囲んだ「${WHEN}」の部分がシェルレベルの定義となり、シェル変数の値で置換されるようです。
実行してみます。
$ ./test2.sh
-----------------------------------------------------
新書発売のお知らせ 2023-11-14
新書「超マシン復活 #5 DEC TOPS-20 レトロなOSの散歩道」
をアマゾンから発売しました。
-----------------------------------------------------
$
【方法-3】AWKの入力ファイル先頭にシェル変数の値を格納する方法
この【方法-3】は、AWKの入力ファイル先頭にシェル変数の値を格納する方法です。
最初にechoコマンドでシェル変数の値をパイプに出力します。
次にcatコマンドで標準入力(-)と対象ファイルをパイプに流してAWKに渡します。
AWK処理では、最初の行(NR==1)のとき入力した値をAWK変数「vdate」に格納します。
そして、それ以外の行を置換処理します。
#!/bin/sh
#
WHEN=`date "+%Y-%m-%d"`
#
echo ${WHEN} |
cat - test.txt |
awk '
NR==1 { vdate = $0; next; }
{
gsub(/{DATE}/ ,vdate);
print $0;
}
'
実行してみます。
$ ./test3.sh
-----------------------------------------------------
新書発売のお知らせ 2023-11-14
新書「超マシン復活 #5 DEC TOPS-20 レトロなOSの散歩道」
をアマゾンから発売しました。
-----------------------------------------------------
$
どの方法がお勧め?
私は、【方法-1】の-vオプションを使うのが1番わかりやすくてお勧めだと思います。
複数のシェル変数をAWKで参照したい場合は、【方法-2】により参照してもよいかもしれません。
【方法-3】のファイルを経由して渡す方法は、あまりお勧めしません。
他の方法を知らなかったときに、苦肉の策としてファイルを経由させることを思いつきました。
この方法で知った、もう一つのことがあります。
それは、catコマンドは “concatenate”(連結させる)ためのコマンドだったという再認識です。
通常は、ファイルをタイプするときに使いますので、ファイルはひとつだけです。
しかし、複数のファイルを指定するとファイルを連結して出力します。
そのとき、ファイル指定がハイフン「-」の場合は、標準入力を対象とします。
echo ${WHEN} | cat - test.txt
従って上記のシェルは、catコマンドにより標準入力の日付とtest.txtファイルの内容を連結して出力します。