if i in [2,4,7]
awkのforループ構文は何ですか?また、以下のコードでこれを実装する方法を学びます。ありがとう
入力する:
$ cat f1
col1,col2,col3,col4,col5,col6,col7
col11,col12,col13,col14,col15,col16,col17
$ cat f2
col1,col2,col03,col4,col5,col06,col7
col11,col12,col13,col14,col015,col16,col17
$ awk -F, '
NR==FNR {
a[FNR][0]=$0 #populate base file records
for(i=1;i<=NF;i++)
a[FNR][i]=$i #populate base file fields
next
}
{
for(i=1;i<=NF;i++)
{
#if(i in [2,4,7]) <***How to chieve this column in list of values*** >
#continue;
if($i!=a[FNR][i])
{
printf "Line#%d, column:%d is different in two files.\n",FNR,i
# ***<TODO print record from first file and second file after printing all mismatch columns>***
}
}
}' f1 f2
予想出力:
Line#1, column:3 is different in two files.
Line#1, column:6 is different in two files.
col1,col2,col3,col4,col5,col6,col7
col1,col2,col03,col4,col5,col06,col7>
Line#2, column:5 is different in two files.
col11,col12,col13,col14,col15,col16,col17
col11,col12,col13,col14,col015,col16,col17>
答え1
デフォルトでは、2つのファイルを行ごとに比較し、特定の列を除外すると、GNUを使用して単語のawk
境界をサポートできます\<
。\>
awk -F, -v skip='2,4,7' 'BEGIN{ filetwo=ARGV[1]; ARGV[1]=""; };{
getline lf2 <filetwo; split(lf2, arr, ",");
for (i=1; i<=NF; i++) {
if ( (skip !~ "\\<"i"\\>") && $i!=arr[i] ) {
print "Line#"FNR, "Column#" i " is different in two files."; mismatch=1; };
};
}; mismatch { print $0; print lf2; mismatch=0; };' file2 file1
またはすべてのawk
バージョン:
awk -F, -v skip_cols='2,4,7' '
BEGIN{ filetwo=ARGV[1]; ARGV[1]=""; split(skip_cols, skip, ","); };{
getline lf2 <filetwo; split(lf2, arr, ",");
for (i=1; i<=NF; i++) {
if ( !(i in skip) && $i!=arr[i] ) {
print "Line#"FNR, "Column#" i " is different in two files."; mismatch=1; };
};
}; mismatch { print $0; print lf2; mismatch=0; };' file2 file1
コードを説明してください。
これ
BEGIN { ... }
詰まった:これは、
入力を読み取る前に最初に行われます。awk
getline
注文する- バラよりgetline
ファイルの変数の使用:
file2から1行を読み取り、それを変数に割り当てますlf2
(今、上記の変数には、filetwo
2番目の引数の名前が含まれていますARGV[1]
)。split()
機能:
読み出し線を分割するファイル2これはlf2
コンマ文字の変数にあり、名前付き配列に格納されます。行の各フィールド,
は、(最初のフィールド)、(2番目のフィールド)、(3番目)などでアドレスarr.
指定されます。arr[1]
arr[2]
arr[3]
以内に
for-loop
氏名次の2つを確認します。- 列番号を表す変数値は変数値には表示されません
i
(; GNU固有の単語境界アンカーなので一致しません).! ~
skip
skip !~ "\\<"i"\\>"
\<
\>
awk
i=2
22
- file1 の列値が、同じ索引を持つ file2 の同じ列と同じであることを確認します。
$i!=arr[i]
;等しくない場合は、一致しない行番号FNR
と差分列インデックスを印刷し、i
制御変数を設定しますmismatch=1
。
- 列番号を表す変数値は変数値には表示されません
mismatch { print ... }
lf2
:不一致が検出され、文に変数が設定され、次の行の変数がリセットされた場合にのみ、mismatch
file1の2行を印刷してから、file2の行を印刷します。if
mismatch=0
答え2
私が正しく理解した場合:
- すべてのフィールドに対してforループを実行しようとしています。 for(i=1;i<=NF;i++) { ... }
- 内部:iが4つの値のいずれかである場合はスキップしたいと思います。 (awkでは、「続き」は現在のforループの残りの部分をバイパスし、次の反復に進みます。
簡単な方法:フィールドをスキップするには、次の技術を使用できます。
BEGIN { skip[2]++; skip[3]++; skip[22]++; skip[23]++ }
....
for(i=1;i<=NF;i++) {
if (i in skip) { continue ; rem="Will skip for values defined in skip array indexes" }
...
BEGINセクションで "skip"を定義する代わりに、スキップインデックスが4つ(1行に1つ)あるファイルがあり、NR = = FNR条件を使用してファイルを読み取り、このスキップの配列で埋めることもできます。 NR!= FNRの場合(ソースファイルを読むとき)、上記の方法を使用してフィールドをスキップできます。
答え3
$ cat tst.awk
BEGIN {
FS=","
split("2,4,7",tmp)
for (i in tmp) {
skipFldNrs[tmp[i]]
}
}
NR==FNR {
old[FNR] = $0
next
}
FNR == 1 {
for (fldNr=1; fldNr<=NF; fldNr++) {
if ( !(fldNr in skipFldNrs) ) {
chkFldNrs[++numToChk] = fldNr
}
}
}
old[FNR] != $0 {
split(old[FNR],o)
for (i=1; i<=numToChk; i++) {
fldNr = chkFldNrs[i]
if ( o[fldNr] != $fldNr ) {
printf "Line#%d, column:%d is different in two files (\"%s\" vs \"%s\").\n", FNR, fldNr, o[fldNr], $fldNr
}
}
}
$ awk -f tst.awk f1 f2
Line#1, column:3 is different in two files ("col3" vs "col03").
Line#1, column:6 is different in two files ("col6" vs "col06").
Line#2, column:5 is different in two files ("col15" vs "col015").