AWKに変数を渡すことはループ内では機能しません。

AWKに変数を渡すことはループ内では機能しません。

YAMLファイルを読み取り、特定の値を出力するawk文があります。値リストからキー値を読み取り、そのキーをawkに渡すループでこのawkを繰り返す必要があります。

YAMLファイルの構造は次のとおりです。

abc:
  NAME: Bob
  OCCUPATION: Technician
def:
  NAME: Jane
  OCCUPATION: Engineer

abc OCCUPATIONキー値を取得したいと仮定し、TECHNICIANインターネット検索を介して私が欲しいものを提供するawkステートメントを設定しました。

> awk 'BEGIN{OFS=""} /^[^ ]/{ f=/^abc:/; next } f{ if (sub(/:$/,"")) abc=$2; else print abc,$1 $2}' test.yml| grep "OCCUPATION:" | cut -d':' -f2
Technician

しかし、このループを使用すると、-vオプションをawkに渡しても結果が出ないようです。

items="abc,def"
for item in $(echo $items | sed "s/,/ /g"); 
do
 echo $item;
 awk -v name="$item" 'BEGIN{OFS=""} /^[^ ]/{ f=/^\name:/; next } f{ if (sub(/:$/,"")) name=$2; else print name,$1 $2}' test.yml| grep "OCCUPATION:" | cut -d':' -f2; 
done

私が設定したデバッグエコーのみが表示されます。

abc
def

私はどこで間違っていますか?変数がawkで正しく解釈されるべきだと思いますか?

編集:Steeldriversのコメントに基づいて入力内容を一部変更しました。

items="abc,def"
for item in $(echo $items | sed "s/,/ /g"); 
do
 echo $item;
 awk -v name="$item" 'BEGIN{OFS=""} /^[^ ]/{ f=name; next } f{ if (sub(/:$/,"")) name=$2; else print name,$1 $2}' test.yml| grep "OCCUPATION:" | cut -d':' -f2; 
done

ただし、OCCUPATIONすべての値が印刷されます。

abc
Technician
Engineer
def
Technician
Engineer

演算子を試してみましたが、~エラーが発生して正しく使用されていないため、値を直接解析することにしましたが、重複が生成されます。

ベストアンサー1

YAML、JSON、XMLなどの構造化テキストで作業するときは、構造を「理解する」パーサーを使用する必要があります。さまざまな種類の構造化テキスト(例:xmlstarletxml、jqjson、yqyamlの場合)ほとんどのプログラミング/スクリプト言語には、構造化テキストを解析して処理するためのライブラリがあります。

PerlコアYAMLモジュールを使用してPerlでこれを行う方法は次のとおりです。

(YAMLモジュールがコアモジュール展開の標準部分として含まれている場合は、perl> = 5.14バージョンが必要です。Perl 5.14は2013年にリリースされました。以前のバージョンのPerlの場合を使用してYAMLをインストールできますcpan

#!/usr/bin/perl

use strict;
use YAML qw(LoadFile);

my $file = shift;            # first arg is the input filename
my $data = LoadFile($file);  # load the yaml data into a hashref variable

# loop over the remaining args (i.e. the keys)
foreach my $item (@ARGV) {
    print "$item\n";
    print $$data{$item}{'OCCUPATION'}, "\n";
}

たとえば、別の名前で保存しyaml.plて実行可能にしますchmod +x yaml.pl

yamlデータがというファイルに保存されている場合は、input.yaml次のように実行できます。

$ ./yaml.pl input.yaml abc def
abc
Technician
def
Engineer

awkやsedのように、これは理解しにくい1行に圧縮できます。

$ perl -MYAML=LoadFile -E '$data=LoadFile(shift);foreach (@ARGV) {say $_;say $$data{$_}{"OCCUPATION"}}' input.yaml abc def
abc
Technician
def
Engineer

Perlは自動的にパラメータを分割することもできます。たとえば、foreachループを次のように変更すると:

foreach my $item (split /\s*,\s*/,join(",",@ARGV)) {

次のように実行できます。

$ ./yaml.pl input.yaml abc def

または

$ ./yaml.pl input.yaml "abc,def"

または任意の組み合わせ(ghiキーとjklキーが使用されていると仮定):

$ ./yaml.pl input.yaml "abc,def" ghi jkl

おすすめ記事