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" }
...
BEGIN 섹션에서 "skip"을 정의하는 대신 건너뛸 인덱스가 4개(한 줄에 1개) 있는 파일이 있고 NR==FNR 조건을 사용하여 파일을 읽고 이 Skip the array로 채울 수도 있습니다. 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").