私の使命は、元のデータのコードの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[]
BEGIN
getline
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
を確認できます。キー(または要素)として存在する場合はそうではありません。val
ref
ref[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 }
mycodes
2番目のフィールドにNULL値を含めることができる場合、2つの間の違いは意味があります。
答え3
与えられた
reffile="mycodes"
while(getline<reffile>0) {ref[$1]=$2}
の空の行は、値が空の文字列でインデックスも空の文字列であるmycodes
要素を作成します。ref
その後、入力ストリームを処理するとき、
newval=ref[val]
newval
毎回$1
( 100
, 101
, 120
, ) には、要素が空でない唯一のインデックスである空の文字130
列が割り当てられます (インデックスは (空) の初期合計と後に生成された各空の要素のインデックス、つまり、、、)。この場合、空の文字列はインデックスの1つなので100
ref
100
""
newval=ref[val]
101
120
130
ref
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
するため、印刷されます。newval
10007
if (newval in ref)
newval
ファイルに空白行がない場合でも、入力ストリームの空白行は同じ謎の動作を引き起こす可能性がありますmycodes
。
あなたの質問で1つ以上の10007
、100007
および「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]
追加されることを指摘しているので、これは配列内で一致するインデックスを検索するより安全な方法です。val
ref
($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