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
基本上,您正在对两个文件和不包括某些列的特定列进行逐行比较;那么,您可以使用 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 中读取一行并将其分配给变量lf2
(请注意上面的filetwo
变量现在包含我们从中读取的第二个参数的名称ARGV[1]
)split()
功能:
我们分割读取的行文件2它是在lf2
逗号字符上的变量中,
并存储在名为的数组中;现在该行的每个字段都由(第一个字段)、(第二个字段)、(第三个)等arr.
寻址。arr[1]
arr[2]
arr[3]
之内
for-loop
陈述我们检查以下两件事:- 指示列号的变量值在变量值中看
i
不到(;并且是字边界锚点,GNU特定的,因此不会匹配);下一个! ~
skip
skip !~ "\\<"i"\\>"
\<
\>
awk
i=2
22
- 检查 file1 中的列值是否与具有相同索引的 file2 中的同一列不相等:
$i!=arr[i]
;如果它们不相同,则打印不匹配的行号FNR
和差异列索引i
,并设置一个控制变量mismatch=1
。
- 指示列号的变量值在变量值中看
mismatch { print ... }
lf2
:仅当检测到不匹配并且在语句mismatch
中设置了变量时,才打印 file1 中的两行,然后打印 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" }
...
您还可以拥有一个包含要跳过的 4 个索引(每行 1 个)的文件,而不是从 BEGIN 部分定义“skip”,并使用 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").