두 개의 열로 구성된 파일이 있습니다.
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