텍스트를 구문 분석하고 검색하고 바꿔야 하는 대용량 파일이 있지만 특정 필드에서는 참조용으로 dest라는 작은 샘플을 공유합니다. 첫 번째 줄은 참조용 제목입니다.
cat dest
ID|NAME|COMPANY|NUMBER
1001|Adam||15001
1002|eve|adam&eve|15002
1003|||
1004|||50000
1005|||50001
일치시킬 패턴, 바꿀 텍스트, 바꿀 텍스트가 포함된 별도의 파일이 있습니다.
cat src
1003||15003
1004|50000|15004
1005|50001|15005
따라서 sed를 사용하여 src 파일의 마지막 2줄에 대해 아래에 제공된 while 루프를 실행할 수 있습니다.
cat src | while IFS=$'|'; read id old new; do sed -i "/^${id}/s/${old}/${new}/" dest; done
그러나 ID=1003
내가 얻은 빈 문자열 의 경우 $old
dest 파일에서 해당 ID에 대한 모든 빈 열을 대체합니다. 나는 이런 상황을 피하고 싶다. 내가 원하는 것은 마지막 필드만 바꾸는 것입니다.
예상하다:
ID|NAME|COMPANY|NUMBER
1001|Adam||15001
1002|eve|adam&eve|15002
1003|||15003
1004|||15004
1005|||15005
열 형식 데이터에 대해 더 세분화되어 있으므로 awk를 사용할 수 있습니다. 그러나 내가 아는 한 awk는 stdout으로 여러 번 인쇄하는데 이는 나에게도 실용적이지 않습니다.
그렇다면 이 작업을 현명하고 간결하게 수행할 수 있는 방법이 있을까요?
답변1
awk 'BEGIN{ FS=OFS="|" }
NR==FNR { id[$1, $2]=$3; next }
{ $4=( ($1, $4) in id? id[$1, $4]: $4) } 1' src dest
FS:에프생산하다에스반복자
OFS:산소산출에프생산하다에스반복자
NR==FNR: 첫 번째 입력 파일에 대해 항상 참인 조건부 관용구입니다.
NR 총 존재 수질소수량오른쪽FNR 이 읽은 기록
은 모든 사람에게 존재합니다 .에프엘리스질소수량오른쪽기록.id[$1, $2]=$3
:관련 awk 배열.이름: id
키: 열#1+열#2
값: 열#3첫 번째 블록은 첫 번째 입력 파일에 대해서만 실행됩니다. 마. 서류소스 코드.
여기서는 $4=($1, $4) in id? id[$1, $4]: $4
두 번째 파일 i의 마지막 열( $NF
or )의 값을 업데이트합니다 $4
. 마. 서류목적지열#1+열#4의 일치하는 키 조합ID배열은 발견되면 값( )을 반환하고 id[$1, $4]
, 그렇지 않으면 현재 값을 복사합니다.
답변2
또 다른 awk
솔루션은 행이 src
순서대로 한 번만 사용된다고 가정합니다. 이를 통해 우리는 src
사용할 때까지 다음 줄을 추적하고 다음 줄을 읽을 수 있습니다 .
awk -F '|' '
BEGIN { OFS=FS }
! have {
getline line <"src"
split(line, pat)
have = 1
}
$1 == pat[1] {
if ($4 == pat[2]) $4 = pat[3]
have = 0
}; 1' dest
이 플래그가 have
설정되지 않거나 0이면 src
다음 줄을 읽고 line
배열로 분할 합니다 pat
. 이것은 ! have
블록 단위로 수행됩니다.
현재 입력 라인의 dest
첫 번째 필드 가 의 첫 번째 요소와 동일 pat
하면 네 번째 필드를 테스트하고 pat[2]
동일한 경우 이를 대체합니다. 그런 다음 pat[3]
플래그 는 have
0으로 재설정되어 에서 새 줄 읽기를 트리거합니다 src
.
1
프로그램 끝에서 후행하면 awk
(수정될 수 있는) 레코드가 출력됩니다.
질문의 데이터 출력을 제공합니다.
ID|NAME|COMPANY|NUMBER
1001|Adam||15001
1002|eve|adam&eve|15002
1003|||15003
1004|||15004
1005|||15005