다음 문서가 주어지면 :
파일 1:
7997,1
7997,2
7997,3
5114,1
5114,2
파일 2:
7997,52,
5114,12,
4221,52,
file2
awk의 데이터와 비교할 값 으로 첫 번째 열을 인덱스로, 두 번째 열을 값으로 사용하여 첫 번째 파일에서 배열을 생성하려면 어떻게 해야 합니까 ?
이 같은:
cat file1 file2 | awk -F, '{if(NF==2){arr[$1]=$2}else{if(arr[$1]){print arr[$1]","$0}}}'
원하는 출력은 다음과 같습니다.
1,2,3,7997,52
1,2,5114,12
답변1
한 가지 방법은 다음과 같습니다.
$ awk -F, -vOFS=, 'NR==FNR{a[$1]=a[$1]","$2; next}
($1 in a){print a[$1],$0}' file1 file2 |
sed 's/^,\(.*\),$/\1/'
1,2,3,7997,52
1,2,5114,12
설명하다
-F, -vOFS=,
: 입력 필드 구분 기호(-F
)와 출력 필드 구분 기호(-vOFS
런타임에 인쇄되는 각 값 사이에 삽입되는 문자열print $1,$2
)를 쉼표로 설정합니다.NR==FNR{a[$1]=a[$1]","$2; next}
:FNR
줄 번호입니다현재의파일NR
은 입력 줄 번호입니다. 읽을 두 개의 파일이 주어 지면awk
이러한 변수는 첫 번째 파일을 읽을 때만 동일합니다. 따라서 첫 번째 블록은NR==FNR{}
첫 번째 파일을 읽을 때만 실행됩니다.이 블록의 코드는
a
첫 번째 필드로 인덱싱된 배열을 만듭니다. 블록이 실행될 때마다 배열의 인덱스에 저장된 항목에 쉼표와 두 번째 필드의 값이 추가됩니다$1
.next
첫 번째 파일의 두 번째 블록이 실행되지 않도록 스크립트 실행을 계속하지 않고 다음 입력 줄로 점프합니다 .첫 번째 실행은
a[$1]
비어 있으므로 배열 시작 부분에 추가 쉼표가 추가됩니다.sed
마지막 항목으로 삭제합니다 .($1 in a){print a[$1],$0}
: 이제 두 번째 파일에 있습니다. 행의 첫 번째 필드가 배열의 인덱스인 경우a
현재 행( )의 해당 인덱스와 연관된 값을 인쇄합니다.a
$0
sed 's/^,\(.*\),$/\1/'
: 줄의 첫 번째 쉼표( )와 일치하고 괄호를 사용하여^,
마지막 쉼표( )\(.*\),$
를 제외한 모든 항목을 캡처합니다. 그런 다음 전체 내용을 캡처된 패턴(\1
)으로 대체합니다. 결과적으로 각 줄의 첫 번째와 마지막 쉼표만 제거됩니다. 이는 스크립트가 줄 시작 부분에 추가하는 추가 쉼표awk
도 제거하는 것입니다file2
. 원하는 출력에도 표시되지 않기 때문입니다.
답변2
이를 달성하기 위해 FNR
및 변수를 사용할 수 있습니다 .NR
awk -F "," '{
if(FNR==NR){
if (a[$1] != ""){
a[$1]=a[$1]","$2
}
else{
a[$1]=$2
}
}
else{
if (a[$1]!= ""){
print a[$1]","$1","$2
}
}
}' file1 file2
답변3
에서 시작하다지진P님의 완벽한 답변그리고 논리를 좀 더 강화해 보세요. 이것은 원래 그의 답변에 대한 코멘트였지만, 너무 길어졌습니다(그리고예그 자체로 유효한 답변입니다.) 여기 있습니다:
awk 'BEGIN {
FS = ","
OFS = ","
}
FNR == NR {
if ($1 in a) {
a[$1] = a[$1] OFS $2
} else {
a[$1] = $2
}
next
}
$1 in a {
print a[$1], $1, $2
}' file1 file2
일반적으로 말해서, 그렇게 하지 말아야 할 특별한 이유가 없는 한 if ($x in myarray)
대신 사용하는 것이 가장 좋습니다 . if (myarray[$x] != "")
배열의 요소가 아직 생성되지 않았는지 확인하려면 첫 번째 버전을 사용하세요. 당신이 알고 있다면가지다생성되었으며 빈 문자열이 아닌지 확인하려면 두 번째 문자열을 사용하세요. 두 번째 방법의 비결은 배열 요소에 이름을 지정하는 것만으로 myarray[$x]
도 해당 값을 확인하는 상황에서도 자동으로 생성된다는 것입니다. 이로 인해 인쇄 배열을 사용할 때 어떤 경우에는 문제가 발생할 수 있습니다 for (index in myarray)
.
그리고 를 사용하는 경우 print var1 "," var2 "," var3
이는 OFS
정확한 사용 사례(출력 필드 구분 기호)입니다. 블록에 OFS를 설정하면 BEGIN
전체 스크립트의 출력 형식을 쉽고 빠르게 변경할 수 있습니다.
마지막으로, 첫 번째 파일에서 하나의 작업을 수행하고 두 번째/기타 파일에서 다른 작업을 수행할 때 FNR == NR
문으로 끝나는 패턴 블록이 if/else 블록보다 더 깔끔하다고 생각합니다.next