タブで区切られた列を持つテキストファイルがありますが、awkを使用して処理したいと思います。
以下はそのようなファイルの例です。
size=1\tname=foo\tweight=1.2
weight=2.5\tname=bar\tsize=2
私が達成したいのは、小数点の4桁に似た内容を持つ列の数値を正規化$field_name=<number>
し、残りは変更せずに維持することです。これには$field_name
awkに渡されたシェル変数があり、その値を正規表現に使用したいと思います。
以下はスニペットです(もちろん動作しません)。私は特に他のツール(sed、Perl、Pythonなど)を使用するソリューションではなく、次のawkスクリプトの5行を修正することに興味があります。
$ cat "${file}" \ # 1
| awk -F "\t" -v field_name="${external_var}" ' # 2
{ # 3
for (i = 1; i <= NF; i++) { # 4
if ($i ~ /$field_name=[0-9]*.?[0-9]+/) { # 5
split($i, kv, "=") # 6
$i = sprintf("%s=%.4f", kv[1], kv[2]) # 7
} # 8
} # 9
print $0 # 10
}'
答え1
これは次のようになります。
if ($i ~ field_name "=[0-9]*.?[0-9]+") ...
または:
regexp = field_name "=[0-9]*.?[0-9]+"
if ($i ~ regexp) ...
.
単一文字はすべて一致します。リテラルを一致させるには(二重引用符で囲む必要があります)またはを含める必要が.
あります。regexp
\.
\\.
[.]
regexp = field_name "=[0-9]*\\.?[0-9]+"
また、正規表現を固定したいと思います。
regexp = "^" field_name "=[0-9]*\\.?[0-9]+$"
その他の注意事項:
cat "${file}"
$file
UUOCなので、起動時に機能せずに-
ファイルを開くことができない場合、実行が継続されるという欠点(リダイレクトを介して)もあります。awk
-v field_name="$external_data"
バックスラッシュを壊します。問題のない別の方法は、環境変数を使用してFIELD="$external_data" awk ...
それをasで参照することです。awk
ENVIRON["FIELD"]
- の内容が
field_name
そのままにコピーされるため、正規表現regexp
として扱われるため、$external_data
正規表現演算子(...)を含めると.+*?{}()[]\^%
正しく動作しないことがあります。 - 一部のロケールおよび
awk
実装では[0-9]
、単純な文字よりも多くの文字が一致します0123456789
(入力に現れる可能性がない(ASCIIではない)文字であると疑われますが)。
そしてperl
:
FIELD=size <"$file" perl -lpe '
s{
(?<![^\t]) # not-preceded by a non-TAB
\Q$ENV{FIELD}=\E # contents of $FIELD taken literally
\K # matched portion starts here
\d*\.?\d+
(?![^\t]) # not followed by a non-TAB
}{
sprintf "%.4f", $&
}gxe'
awk
これは上記の問題をまったく示していません(また、テキストとバイナリデータの混在、またはユーザーのロケールや他の文字セットでエンコードされたテキストなどの誤ったテキストを含む入力よりも優れています)。