데이터가 필드로 구분된 텍스트 파일의 행을 추출/변경하는 방법은 무엇입니까?

데이터가 필드로 구분된 텍스트 파일의 행을 추출/변경하는 방법은 무엇입니까?

명령줄에서 필드 기반 데이터를 조작하는 방법은 무엇입니까? 예를 들어

  • N번째 필드가 있는 행만 인쇄하는 방법은 무엇입니까 foo?
  • N번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까 foo?
  • N번째 필드가 일치하는 행만 인쇄하는 방법은 무엇입니까 foo?
  • N 필드를 로 어떻게 변경합니까 foo?

*nix 시스템에서 현장 기반 데이터를 조작하는 데 도움이 되는 표준 방법론이나 도구 세트가 있습니까?

답변1

필드 작업 시 사용할 수 있는 두 가지 기본 접근 방식은 다음과 같습니다. i) 필드를 이해하는 도구 사용 ii) 정규식 사용. 둘 중 전자가 일반적으로 더 강력하고 간단합니다.

*nix의 많은 일반적인 도구는 필드를 처리하도록 명시적으로 설계되었거나 이를 용이하게 하는 영리한 트릭을 가지고 있습니다.

1. 분야를 이해하는 도구를 사용하세요

1.1아크

여기서의 고전적인 도구는 awk각 입력 줄을 자동으로 필드로 분할한 다음(필드 구분 기호는 기본적으로 공백이지만 플래그를 사용하여 변경할 수 있음 ) 아래와 같이 -F이러한 필드를 스크립트에서 사용할 수 있습니다.awk$nn필드 번호입니다. 첫 번째 필드는 이고 $1, 두 번째 필드는 $2이런 식입니다.

  • 세 번째 필드가 있는 줄을 인쇄합니다 foo.

    awk '$3=="foo"' file
    

    구분 기호를 다음으로 변경하십시오.:

    awk -F":" '$3=="foo"' file
    

    기본 작업은 awk인쇄입니다. 따라서 위 명령은 세 번째 필드가 있는 모든 줄을 인쇄합니다 foo. 를 사용하면 -F필드 구분 기호를 설정하고 정규식을 사용할 수도 있습니다.

  • 세 번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까 foo?

    awk '$3!="foo"' file
    
  • 세 번째 필드가 일치하는 행만 인쇄하는 방법은 무엇입니까 foo?

    foo패턴과 일치하는 필드(예: match foobar) 를 찾고 있다면 ~대신 다음 을 사용하세요 ==.

    awk '$3~/foo/' file
    
  • 세 번째 필드가 일치하지 않는 행만 인쇄하려면 어떻게 해야 합니까 foo?

    awk '$3!~/foo/' file
    
  • 세 번째 필드를 로 어떻게 변경합니까 foo?

    awk '$3="foo"' file
    

1.2 펄

또 다른 옵션은 perl한 줄입니다. awk와 마찬가지로 Perl은 모든 기능을 갖춘 스크립트 언어이지만 스크립트를 입력으로 사용하여 명령줄 프로그램으로 실행할 수도 있습니다. 동작은 명령줄 스위치를 통해 수정되며, 이 질문과 가장 관련이 있는 스위치는 다음과 같습니다.

  • -eperl: 실행되어야 하는 스크립트입니다.
  • -n: 입력 파일을 한 줄씩 읽습니다.
  • -p:Apply; 주어진 스크립트 다음에 각 입력 줄을 인쇄합니다 -e.
  • -lprint:각 입력 줄에서 후행 줄 바꿈을 제거하고 각 호출에 줄 바꿈을 추가합니다.
  • -a:awk-mode, 각 입력 라인을 배열로 분할합니다 @F.
  • -F: 필드 구분 기호 -a.

한 가지 중요한 차이점 은 스위치가 파일을 배열로 분할한다는 것 awk입니다 . Perl에서는 배열이 1이 아닌 0부터 시작합니다. 즉, 두 번째 필드는 실제로 가 아닙니다 . 이 모든 것을 고려하면 위의 내용은 다음과 같습니다.perl-a$F[1]$F[2]perl

  • 세 번째 필드가 있는 줄을 인쇄합니다 foo.

    perl -ane 'print if $F[2] eq "foo"' file
    

    구분 기호를 다음으로 변경하십시오.:

    perl -F":" -ane 'print if $F[2] eq "foo"' file
    

    awk와 달리 perl정규식을 필드 구분 기호로 사용할 수 없습니다. 특정 문자나 문자열이어야 합니다.

  • 세 번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까 foo?

    perl -ane 'print unless $F[2] eq "foo"' file
    
  • 세 번째 필드가 일치하는 행만 인쇄하는 방법은 무엇입니까 foo?

    perl -ane 'print if $F[2]=~/foo/' file
    
  • 세 번째 필드가 일치하지 않는 행만 인쇄하려면 어떻게 해야 합니까 foo?

    perl -lane 'print unless $F[2]=~/foo/' file
    
  • 세 번째 필드를 로 어떻게 변경합니까 foo?

    Perl에서는 이것이 약간 문제가 됩니다. 일반적인 접근 방식은 배열의 값을 변경한 @F다음 배열을 인쇄하는 것입니다. 간단한 공백으로 구분된 파일의 경우 다음과 같이 쉽습니다.

    perl -lane '$F[2]="foo"; print "@F"' file
    

    다른 구분 기호를 사용하면 배열이 필요합니다 join. 그렇지 않으면 공백으로 구분되어 인쇄됩니다.

    perl -F: -lane '$F[2]="foo"; print join ":",@F' file
    

2. 정규식을 사용하세요

여기서의 아이디어는 정규식(줄여서 "regex")을 사용하여 줄에서 대상 문자열의 위치를 ​​정의하는 것입니다. 예를 들어 필드가 로 구분된 파일에서 :첫 번째 필드(첫 번째 필드) 앞의 모든 항목을 일치시킨 :다음 두 번째 필드를 찾아 두 번째 필드를 찾을 수 있습니다.

^[^:]*:[^:]*:

이 정규 표현식의 의미는 다음과 같습니다.

  • ^: 줄의 시작;
  • [^]: 부정된 문자 클래스입니다. [^:]" :이외의 것"을 의미합니다.
  • *: 0개 이상의 이전 패턴;
  • ::문자 그대로의 의미 :;

전체적으로 이는 첫 번째 [^:]*필드가 첫 번째 필드이고 두 번째 필드가 두 번째 필드임을 의미합니다. 분명히 이것은 14번째 필드를 찾는 경우 그다지 실용적이지 않지만 더 간단한 작업에는 유용합니다. 그렇다면 데이터를 조작하기 위해 이를 어떻게 구현합니까? 이를 수행하는 데는 다양한 도구가 있습니다. 이 예에서는 를 사용 sed하지만 을 사용 awk하거나 perl매우 유사한 작업을 수행 할 수도 있습니다 python.

  • 두 번째 필드가 있는 행만 인쇄하려면 어떻게 해야 합니까 foo?

    sed -n '/^[^:]*:foo:/p' file
    

    -n일반 출력을 억제합니다 . /regex/p즉, "정규식과 일치하는 모든 줄을 인쇄합니다.

  • 두 번째 필드가 아닌 행만 인쇄하는 방법은 무엇입니까 foo?

    sed '/^[^:]*:foo:/d' file
    

    위의 논리와 반대입니다. 여기서는 /regex/d"정규식과 일치하는 모든 줄을 제거합니다."를 의미합니다.

  • 두 번째 필드가 일치하는 행만 인쇄하려면 어떻게 해야 합니까 foo?

    sed -n '/^[^:]*:[^:]*foo/p' file
    
  • 두 번째 필드가 일치하지 않는 행만 인쇄하려면 어떻게 해야 합니까 foo?

    sed '/^[^:]*:[^:]*foo/d' file
    
  • 두 번째 필드를 로 어떻게 변경합니까 foo?

    sed 's/\([^:]*:\)[^:]*/\1foo/' file 
    

    또는 대체는 sed간단한 숫자 플래그 반복을 사용하여 패턴 발생을 직접 해결할 수 있으므로 다음과 같습니다.

    sed 's/[^:]*/foo/2' file
    

관련 정보