AWK에서 입력 필드를 제거하는 방법은 무엇입니까?

AWK에서 입력 필드를 제거하는 방법은 무엇입니까?

awk(또는 ) 을 사용하여 일부 데이터를 변환 중이며 gawk출력을 다시 인쇄하기 전에 입력 필드 중 하나를 제거하고 싶습니다.

내가 달성하고 싶은 것은 다음과 같습니다

~ $ echo 'field1,field2,field3' | awk -F, '{transform($1); delete($2); print $0;}'
new_field1,field3

$2결과적으로 빈 문자열을 할당할 수는 없습니다 new_field1,,field3(쉼표 두 개에 주의).

원하는 필드만 명시적으로 인쇄할 수 있지만 필드가 3개보다 훨씬 많고 끝에 선택적 필드가 있으므로(여기에는 표시되지 않음) 그다지 우아하지는 않습니다. 그래서 print $0먼저 일부 필드를 삭제하는 것을 선호합니다.

어떤 아이디어가 있나요?

답변1

awk에서 필드를 삭제하는 것은 매우 어렵습니다. 이는 간단한(종종 필요한) 작업처럼 보이지만 생각보다 어렵습니다.

바라보다추가 구분 기호가 인쇄되지 않도록 awk에서 필드를 완전히 제거하는 방법이 있습니까? Stack Overflow의 훌륭한 팁입니다.

rmcol()U&L에 복사본이 있도록 @ghoti의 답변에서 함수를 복사했습니다 .

function rmcol(col,     i) {
  for (i=col; i<NF; i++) {
    $i=$(i+1)
  }
  NF--
}

현재 입력 행에서 지정된 열을 제거하고 일치를 위해 필드 카운터( NF)를 감소시킵니다.

나는 당신의 기능이 무엇인지 모르기 transform()때문에 그것을 반복하려고 시도조차 하지 않을 것입니다. 그러나 다음은 rmcol()한 줄로 사용하는 예입니다:awk

$ echo 'field1,field2,field3' | awk -F, -v OFS=, '
  function rmcol(col,     i) {
    for (i=col; i<NF; i++) {
      $i=$(i+1)
    }
    NF--
  }

  { rmcol(2); print; }
  '
field1,field3

그런데 입력 행에서 여러 필드를 제거해야 하는 경우 가장 쉽고 쉬운 방법은 역순으로 제거하는 것입니다. 그건,가장 높은 숫자의 필드를 먼저 삭제하세요.. 왜? 낮은 번호가 매겨진 필드가 삭제될 때마다 높은 번호가 매겨진 필드의 번호가 다시 매겨져 어떤 필드 번호가 어떤 필드에 속하는지 추적하기 어렵기 때문입니다.


그런데 delete()in은 awk배열의 요소를 제거하는 데 사용되며 입력 행에서 필드를 제거하는 데 사용되지 않습니다. split()각 입력 라인( on )을 배열에 넣고 두 번째 배열 요소를 제거 할 수 있지만 , 그런 다음 각 필드를 쉼표( 또는 ) 로 구분하여 배열을 인쇄하는 함수 FS를 작성해야 합니다 .join()OFS

awk이렇게 하는 것조차 모든 배열이 연관 배열이기 때문에 예상보다 더 복잡할 것입니다 (즉,아니요숫자 인덱스) - 그래서delete(array[2]) 에 익숙해배열 요소 3+를 요소 2+로 자동으로 이동합니다. delete()입력 필드에서와 마찬가지로 배열에서도 거의 동일한 작업을 수행하려면 자체 래퍼 함수를 ​​작성해야 합니다 .rmcol()

답변2

몇 가지 대안

1) 입력을 전처리하여 먼저 필드를 제거합니다. cut필드 구분 기호가 단일 문자인 경우 이 작업을 쉽게 수행할 수 있습니다.

$ s='field1,field2,field3'
$ # use 'cut -d, -f1,3-' if --complement option is not available
$ echo "$s" | cut -d, --complement -f2
field1,field3
$ echo "$s" | cut -d, --complement -f2 | awk 'BEGIN{FS=OFS=","} {$1="new"} 1'
new,field3

2) 사용perl

$ # indexing starts from 0, the array @F contains the input fields
$ # $#F will give index of last element in the array
$ echo "$s" | perl -F, -lane '$F[0]="new"; print join ",", @F[0,2..$#F]'
new,field3

답변3

$0을 재정의하면 gensub스크립트가 더 간단해질 수 있습니다.

주어진 입력에서 필드 2와 3을 제거하려면 $0에서 필드 제거를 사용 gensub하고 다음과 같이 $0(및 모든 필드)를 재생성할 수 있습니다.

> echo 'field1,field2,field3' \
    | awk -F, '{OFS=","; \
                transform($1); \
                $0=gensub(/[^,]*,/,"",2); \
                print}'
new_field1,field3

이는 print와 동일합니다 print $0.

관련 정보