awkのパターン内でシェル変数を使用する

awkのパターン内でシェル変数を使用する

タブで区切られた列を持つテキストファイルがありますが、awkを使用して処理したいと思います。

以下はそのようなファイルの例です。

size=1\tname=foo\tweight=1.2
weight=2.5\tname=bar\tsize=2

私が達成したいのは、小数点の4桁に似た内容を持つ列の数値を正規化$field_name=<number>し、残りは変更せずに維持することです。これには$field_nameawkに渡されたシェル変数があり、その値を正規表現に使用したいと思います。

以下はスニペットです(もちろん動作しません)。私は特に他のツール(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}"$fileUUOCなので、起動時に機能せずに-ファイルを開くことができない場合、実行が継続されるという欠点(リダイレクトを介して)もあります。awk
  • -v field_name="$external_data"バックスラッシュを壊します。問題のない別の方法は、環境変数を使用してFIELD="$external_data" awk ...それをasで参照することです。awkENVIRON["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これは上記の問題をまったく示していません(また、テキストとバイナリデータの混在、またはユーザーのロケールや他の文字セットでエンコードされたテキストなどの誤ったテキストを含む入力よりも優れています)。

おすすめ記事