AWKの配列にはコード記述が必要です。

AWKの配列にはコード記述が必要です。

私の使命は、元のデータのコードの1つが参照リストから読み取られた新しいコードに置き換えられるリストを作成することです。この場合、変更は1つだけですが、必要に応じて参照リストに追加することもできます。

参照リスト(mycodes)には次の値があります。

100,100007

データは3桁のコードのストリームですが、100のコードは残りのストリームと一緒に5桁のコードで記述する必要があります。以下のようにAWKプログラムを使用しました。

BEGIN{
FS=","
reffile="mycodes"
while(getline<reffile>0) {ref[$1]=$2}
}
{
val=$1
newval=ref[val]

if (newval in ref) { outval=val}
else               {outval=newval}

print outval
}

入力データファイルには次の値が含まれます。

100
101
120
130
100

プログラムの実行時に正しい出力を生成します。

100007
101
120
130
10007

ただし、参照ファイルの最初の項目の後にスペースがある場合にのみ機能します。空白がない場合、プログラムは 100007 以外の内容を出力として生成しません。

私はこのAWKプログラムのロジックで正確に何が起こっているのかわからず、誰かがそれを説明するのに役立つかもしれません。特にif (newval in ref)

答え1

getline以下を使用してパディングを使用するには、$0次の方法を参照してください。http://awk.freeshell.org/AllAboutGetline):

while ( (getline < reffile) > 0 ) {
    ref[$1] = $2
}

スクリプトの残りの部分は1行だけで構成する必要があります。

{ print ( $1 in ref ? ref[$1] : $1 ) }

したがって、スクリプト全体は次のようになります。

BEGIN {
    FS = ","
    reffile = "mycodes"
    while ( (getline < reffile) > 0 ) {
        ref[$1] = $2
    }
}
{ print ( $1 in ref ? ref[$1] : $1 ) }

"mycodes"ファイル名を保持するために変数を作成し、それをパラメータとして渡したくない理由があるとします。

またはこれを行うこともできます:

BEGIN { FS = "," }
NR==FNR { ref[$1] = $2; next }
{ print ( $1 in ref ? ref[$1] : $1 ) }

そして電話してください。これはループを使用してパディングするよりも少し効率的ではありませんが、ほとんどawk 'script' mycodes fileのアプリケーションでは問題になる可能性がなく、明らかによりクリーンでエラーになりやすいコードを使用します。refs[]BEGINgetline

do は awk が現在のレコードを書き換えることを強制しないため、print ( $1 in ref ? ref[$1] : $1 )do または類似のものよりも効率的ですが、やはりif ($1 in ref) $1=ref; print $1言葉ではありません。

問題はありますが、既存のスクリプトは説明したように失敗しない可能性があり、実際の問題はDOS行の終わりです(参照)https://stackoverflow.com/questions/45772525/why-does-my-tool-output-overwrite-itself-and-how-do-i-fix-it?)。

答え2

val=$1
newval=ref[val]
if (newval in ref) { outval=val }
else               { outval=newval }

したがってval、デフォルトの入力ファイルからこれらの値を読み取る(たとえば、または100.123などrefの項目を含むペアの場合、キーとして存在するかどうか(つまり、要素が存在するかどうか)ref[100]=100007を確認できます。キー(または要素)として存在する場合はそうではありません。valrefref[val]ref[val]ref[ref[val]]

だからそれをやってくださいif (val in ref)

まあ、もしそうならするnewval存在する場合は、そこに見つかった値(現在の場所)を使用できます。いいえ、前の値(val)。だからこうやって

val=$1
newval=ref[val]
if (val in ref) { outval=newval }
else            { outval=val }

@αГsнιιが言及したことに加えて、現在割り当て問題があります。newval=ref[val] 作る ref[val]空の文字列がまだ存在しない場合は値として使用されるため、これに対処する必要があります。

完全に取り外し、テスト後にのみnewval使用してください。ref[val]

val=$1
# newval=ref[val]     # remove this line
if (val in ref) { outval=ref[val] }
else            { outval=val }

またはそこに置いて空の文字列をテストします。

val=$1
newval=ref[val]
if (newval != "") { outval=newval }
else              { outval=val }

mycodes2番目のフィールドにNULL値を含めることができる場合、2つの間の違いは意味があります。

答え3

与えられた

reffile="mycodes"
while(getline<reffile>0) {ref[$1]=$2}

の空の行は、値が空の文字列でインデックスも空の文字列であるmycodes要素を作成します。ref

その後、入力ストリームを処理するとき、

newval=ref[val]

newval毎回$1( 100, 101, 120, ) には、要素が空でない唯一のインデックスである空の文字130列が割り当てられます (インデックスは (空) の初期合計と後に生成された各空の要素のインデックス、つまり、、、)。この場合、空の文字列はインデックスの1つなので100ref100""newval=ref[val]101120130ref

if (newval in ref) { outval=val}
else               {outval=newval}

if (newval in ref)成功した印刷値は、入力ストリーム(val、from)val=$1の現在の値です。

一方ref、空の文字列でインデックス付けされた要素がない場合(空の行がない場合に発生mycodes)、空の文字列はif (newval in ref)毎回失敗します。newvalその後、newval(空白行)が印刷されます。

どちらの場合もyesの場合は$1失敗100するため、印刷されます。newval10007if (newval in ref)newval

ファイルに空白行がない場合でも、入力ストリームの空白行は同じ謎の動作を引き起こす可能性がありますmycodes

あなたの質問で1つ以上の10007100007および「5桁のコード」がスペルが間違っていて、実際には常に10007(5桁のコード)を意味すると仮定すると、AWKプログラムは次のように書き直されます。

awk -v FS=, '
  NR == FNR {
    ref[$1] = $2
    next
  }
  ($1 in ref) {
    $1 = ref[$1]
  }
  1
' ./mycodes -

または

awk '
  BEGIN {
    FS=","
    while ( (getline < "mycodes") > 0 )
      ref[$1] = $2
  }
  ($1 in ref) {
    $1 = ref[$1]
  }
  1
' -

(ありがとうございます。αГsнim実際にはインデックスとしてnewval=ref[val]追加されることを指摘しているので、これは配列内で一致するインデックスを検索するより安全な方法です。valref($1 in ref)

答え4

主な問題はこの行にありますnewval=ref[val]。ここで変数はvalキーとして機能します($1で同じval=$1)。これは実際に意味しますnewval=ref[$1]。この行にキーが存在すると、newval変数の内容はref []配列の値に設定されます。ref[val]それ以外の場合は空の値に設定されます。つまり、newval=ref[val]キーが配列に見つからない場合は、キーがnull値で配列に追加され、変更を望まない場合は、将来の問題が発生する可能性があります。配列サイズ/インデックス、またはファイルが大きい場合は、使用可能なメモリを超えるか、スクリプトの速度が大幅に遅くなる可能性があります。

... if-elseステートメントでテストしている場合はnewval常に実行されます。else部分。

if (newval in ref) {
        outval = val;    ## this section never runs
} else {
        outval = newval  ## this sections runs for every tests
}

newval=ref[val]したがって、キーが行に存在する限り、そのoutvalキーの値が使用され、それ以外の場合はnullに設定されます。に印刷すると、print outvalそのキーの値がref []配列にある場合は出力され、それ以外の場合は空行が出力されます。

簡単な修正(追加の改善は必要ありません)は、次のように行を変更します。

newval = (val in ref)?ref[val]:val

コマンドは次のように書くことができます。

$ awk 'BEGIN{ FS="," }
    NR==FNR   { ref[$1]=$2; next }
   ($1 in ref){ $1=ref[$1] }1' reference infile
100007
101
120
130
100007

$ cat reference
100,100007
$ cat infile
100
101
120
130
100

関連情報