파일의 특정 열에 Diff 사용

파일의 특정 열에 Diff 사용

파일의 특정 열에 대해 diff를 사용할 수 있습니까?

파일 1

Something  123 item1
Something  456 item2
Something  768 item3
Something  353 item4

파일 2

Another   123 stuff1
Another   193 stuff2
Another   783 stuff3
Another   353 stuff4

출력 (예상)

Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3

각 파일의 두 번째 열을 원하면 diff결과에 차이 열이 포함되지만 전체 행이 포함됩니다.

답변1

awk파일 열을 비교하는 데 더 나은 도구입니다. 예를 들어 다음 질문에 대한 답변을 참조하세요.서로 다른 파일의 두 열을 비교하고 일치하면 인쇄합니다.-- 열과 일치하는 행을 인쇄하는 데에도 비슷한 답변이 있습니다.

라인을 인쇄하고 싶기 때문에아니요awk일치하면 file2의 열 2에 포함된 줄을 인쇄하는 명령을 만들 수 있습니다 .아니요file1을 참조하세요.

$ awk 'NR==FNR{c[$2]++;next};c[$2] == 0' file1 file2
Another   193 stuff2
Another   783 stuff3

terdon에서도 비슷하게 설명했듯이위의 질문,

  • NR==FNR: NR은 현재 입력 라인 번호이고, FNR은 현재 파일의 라인 번호입니다. 두 파일은 첫 번째 파일을 읽는 경우에만 동일합니다.
  • c[$2]++; next: 첫 번째 파일인 경우 두 번째 필드를 c배열로 저장합니다. 그런 다음 첫 번째 파일에만 적용되도록 다음 줄로 이동합니다.
  • c[$2] == 0: else 블록은 이것이 두 번째 파일인 경우에만 실행되므로 해당 파일의 필드 2가 이미 표시되었는지 확인하고( c[$2]==0), 그렇다면 해당 행을 인쇄합니다. 에서 awk기본 작업은 줄을 인쇄하는 것이므로 c[$2]==0true인 경우 줄이 인쇄됩니다.

그러나 열 2가 file2의 행과 일치하지 않는 file1의 행도 원합니다. 동일한 명령에서 위치를 간단히 바꾸면 이를 얻을 수 있습니다.

$ awk 'NR==FNR{c[$2]++;next};c[$2] == 0' file2 file1
Something  456 item2
Something  768 item3

이제 이를 두 번 사용하여 원하는 출력을 생성할 수 있습니다 awk. 아마도 더 많은 전문 지식을 가진 사람 awk이 한 번에 할 수 있을 것입니다.

질문에 태그를 달았 /ksh으므로 korn 쉘을 사용하고 있다고 가정합니다. ksh예를 들어 diff에 대한 함수를 정의하여 작업을 더 쉽게 만들 수 있습니다 diffcol2.

diffcol2()
{
   awk 'NR==FNR{c[$2]++;next};c[$2] == 0' $2 $1      
   awk 'NR==FNR{c[$2]++;next};c[$2] == 0' $1 $2      
}

이것은 원하는 동작을 갖습니다:

$ diffcol2 file1 file2
Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3

답변2

나는 diff가 (cut과 결합하더라도) 이것을 처리할 만큼 충분히 유연하지 않다고 생각합니다. 실제로 원하는 것은 file2에 없는 file1의 키이고 그 반대의 경우도 마찬가지입니다. 엄밀히 말하면 한 줄씩 차이가 있는 것은 아닙니다. 입력 파일이 크면 Perl을 사용하지만 작은 파일의 경우 이 awk 스크립트는 제공된 입력으로 작동합니다.

%cat a.awk

BEGIN {
  while (getline < "file1") {
    line=$0;
    split(line,f," ");
    key=f[2];
    f1[key]=line
  }
  while (getline < "file2") {
    line=$0;
    split(line,f," ");
    key=f[2];
    f2[key]=line
  }
}
END {
  for (c in f1) {
    if (c in f2 == 0) print f1[c]
  }
  for (c in f2) {
    if (c in f1 == 0) print f2[c]
  }
}

실행 방법은 다음과 같습니다(awk에는 입력 파일이 인수로 필요하므로 /dev/null 트릭에 유의하세요.

%awk -f a.awk /dev/null
Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3

답변3

다음과 같은 방법으로 한 번에 작업을 수행할 수 있습니다.

$ awk '{t[$2]=t[$2]$0"\n";NR==FNR?a[$2]=1:b[$2]=1}END{for(i in t)if(a[i]!=b[i])printf"%s",t[i]}' file1 file2
Another   193 stuff2
Something  456 item2
Something  768 item3
Another   783 stuff3

설명하다:

  • 각 행에 대해 다음을 수행합니다.
    • {t[$2]=t[$2]$0"\n";t해당 키로 인덱싱된 테이블에서 동일한 키를 가진 모든 행을 조인합니다.
    • NR==FNR?a[$2]=1:b[$2]=1}키가 첫 번째 파일에 있으면 a테이블에 넣고, 그렇지 않으면 b;
  • END마지막에:
    • {for(i in t)표의 각 키에 대해 다음을 수행합니다 t.
      • if(a[i]!=b[i])키가 하나의 파일에만 존재하는 경우:
        • printf"%s",t[i]}모든 행을 인쇄하려면 이 키를 사용하십시오.

이는 키가 중복된 경우(키 없이 다른 파일의 모든 줄을 인쇄하는 경우)에도 작동하지만 줄의 순서는 유지되지 않습니다(줄은 키별로 사전순으로 인쇄됩니다).

관련 정보