파일 변환

파일 변환

두 개의 열로 구성된 파일이 있습니다.

A,val1
A,val2
A,val3
B,val1
B,val2
B,val3

나에게 필요한 것은 첫 번째 열의 모든 고유 값에 대해 두 번째 열이 수평이 되도록 출력을 변환할 수 있는 것입니다.

A,val1,val2,val3
B,val1,val2,val3

BASH나 AWK를 사용하는 것이 가장 좋은 방법인지 잘 모르겠습니다. 둘을 조합한 것일 수도 있습니다. 누구든지 올바른 방향을 알려주세요.

답변1

awk만 사용:

$ awk -F, 'BEGIN{OFS=FS} {a[$1] = a[$1] == "" ? $2 : a[$1] FS $2} END {for(i in a) print i,a[i]}' file
A,val1,val2,val3
B,val1,val2,val3

출력 순서는 보장되지 않습니다. GNU awk로 수정하기는 쉽지만 다른 구현에서는 더 어렵습니다. 입력 데이터는 정렬할 필요가 없습니다.

그렇지 않으면 GNU datamash를 사용하십시오.

datamash -t, groupby 1 collapse 2 < file

(입력이 정렬되지 않은 경우 추가 -s) 또는 Miller를 사용하여

mlr --nidx --fs ',' nest --implode --values --across-records --nested-fs ',' -f 2 file

또는 더 컴팩트하고 업데이트된 버전

mlr --nidx --fs ',' nest --ivar ',' -f 2 file

답변2

쉘 스크립트를 사용하여 이 문제를 해결하는 방법은 여러 가지가 있지만 저는 덜 표준적인 도구를 사용하는 것을 선호합니다.밀러. apt install miller우분투/데비안에 설치할 수 있습니다 . 나는 Miller의 동사가 bash나 awk보다 이러한 유형의 문제를 생각하는 데 더 자연스러운 도구라고 생각합니다.

질문에 지정된 데이터가 다음 위치에 저장되어 있는 경우 INPUT_FILE:

A,val1
A,val2
A,val3
B,val1
B,val2
B,val3

다음은 밀러의 것nest동사여러 레코드(행)를 필드 2에 여러 값이 있는 단일 레코드로 묶고 필드 2를 여러 필드로 확장하는 데 사용할 수 있습니다.

mlr --ocsv --headerless-csv-output \
  nest --implode --values --across-records -f 2 then \
  nest --explode --values --across-fields -f 2 INPUT_FILE

그러면 원하는 출력이 생성됩니다.

A,val1,val2,val3
B,val1,val2,val3

Miller는 이 작업을 수행하는 더 쉬운 방법을 가지고 있을 수 있지만 이것이 제가 찾은 첫 번째 솔루션입니다.

답변3

출력 순서를 보장하려면 다음 awk 코드를 사용하십시오. 여기서 우리는 연관 배열(associative array)로도 알려진 해시(see[...])를 유지 관리합니다. 이 해시는 새 키($1)가 발견될 때마다 증가하는 카운터에 의해 입력됩니다.

$ awk -F "," '
    prev != $1 { prev = $1 }
    !($1 in a) { seen[++n] = $1 }
    { a[$1] = a[$1] FS $2 }
    END {
      for (i=1; i<=n; i++) {
        print seen[i] a[seen[i]] 
      }
    }
  ' file
A,val1,val2,val3
B,val1,val2,val3

답변4

모든 Unix 시스템의 모든 쉘에서 awk를 사용하고 한 번에 1개의 $1 키 블록만 메모리에 저장하면서 출력 라인 순서를 유지합니다.

$ awk '
    BEGIN { FS=OFS="," }
    $1!=p { printf "%s%s", rec, sep; rec=p=$1; sep=ORS }
    { rec = rec OFS $2 }
    END { print rec }
' file
A,val1,val2,val3
B,val1,val2,val3

관련 정보