AWK는 1개 열의 내용을 기준으로 입력 CSV를 여러 출력 파일로 분할합니다.

AWK는 1개 열의 내용을 기준으로 입력 CSV를 여러 출력 파일로 분할합니다.

파일 data.csv에는 다음과 같은 데이터가 있습니다

1,avocado,mexican green fruit
1,kiwi,green fruit
1,banana,yellow fruit
1,mango,yellow fruit

데이터를 과일 카테고리로 정리하기 위해

awk -F ',' '{print >> ($3 ".csv")}' data.csv

mexican green fruit.csv, green fruit.csv, 3개의 파일을 생성합니다 .yellow fruit.csv

이 파일 이름의 공백을 밑줄로 바꾸고 싶습니다._

따라서 파일 이름은 mexican_green_fruit.csv,, 이어야 합니다.green_fruit.csvyellow_fruit.csv

awk그렇게 하려면 이 안감의 도움이 필요해요

awk유일한 답을 찾고 있어요

답변1

GNU awk에 대한 awk 전용 답변(OP에서 요청한 대로)은 다음과 같습니다.

awk -F',' '{print > gensub(/[[:space:]]+/,"_","g",$3) ".csv"}' data.csv

입력이 너무 작아서 "열린 파일이 너무 많음" 임계값을 초과할 수 없는 경우 POSIX awk에 대한 awk 전용 대답은 다음과 같습니다.

awk -F',' '{out=$3 ".csv"; gsub(/[[:space:]]+/,"_",out); print > out}' data.csv

"열린 파일이 너무 많음" 임계값을 초과할 가능성이 있는 경우 POSIX awk에 대한 awk 전용 대답은 다음과 같습니다.

awk -F',' '{out=$3 ".csv"; gsub(/[[:space:]]+/,"_",out); if (!seen[$3]++) printf "" > out; print >> out; close(out)}' data.csv

그러나 마지막 것은 각 쓰기에 대해 출력 파일을 닫았다가 다시 열고 $3각 값을 메모리에 저장할 수 있다고 가정하기 때문에 속도가 느립니다. 변경된 경우에만 출력 파일을 닫아 효율성을 향상시킬 수 있습니다.

awk -F',' '$3 != prev {close(out); out=$3 ".csv"; gsub(/[[:space:]]+/,"_",out); if (!seen[$3]++) printf "" > out; prev=$3} {print >> out}' data.csv

단순히 awk를 사용하는 것이 아니라 정렬 및 자르기를 위한 DSU(장식/정렬/장식 해제) 관용구인 POSIX awk를 사용한다는 대답에 만족한다면 다음은 sort처리 할 수 있는 모든 크기의 입력 파일에 대해 효율적이고 강력하게 작동합니다. (요청 페이징 등을 사용하여 매우 큰 파일을 처리하도록 설계되었습니다.) 그리고 출력 파일 수에 관계없이 다음을 수행합니다.

$ cat tst.sh
#!/usr/bin/env bash

awk '
    BEGIN{ FS=OFS="," }
    { print $3,NR,$0 }
' "${@:-}" |
sort -t',' -k1,1 -k2,2n |
cut -d',' -f3- |
awk '
    BEGIN{ FS=OFS="," }
    $3 != prev {
        close(out)
        out = $3 ".csv"
        gsub(/[[:space:]]+/,"_",out)
        prev = $3
    }
    { print > out }
'

$ ./tst.sh data.csv

$ head *.csv
==> data.csv <==
1,avocado,mexican green fruit
1,kiwi,green fruit
1,banana,yellow fruit
1,mango,yellow fruit

==> green_fruit.csv <==
1,kiwi,green fruit

==> mexican_green_fruit.csv <==
1,avocado,mexican green fruit

==> yellow_fruit.csv <==
1,banana,yellow fruit
1,mango,yellow fruit

DSU에 대한 자세한 내용은 다음을 참조하세요.https://stackoverflow.com/questions/71691113/how-to-sort-data-based-on-the-value-of-a-column-for-part-multiple-lines-of-af/71694367#71694367.

답변2

이는 다음과 같은 함수를 사용하여 수행할 수 있습니다.

awk -F, '
  function csvfile(name) {
    gsub(/[[:space:]]+/, "_", name)
    return name".csv"
  }
  {print >> csvfile($3)}'

여기에서 각 시퀀스에 대한 하나 이상의 공백 문자(공백, 탭, cr... 포함)가 로 대체됩니다 _.

답변3

(gnu awk 또는 이와 유사한 것을 사용하여) 다음과 같이 실행할 수 있습니다

awk -F, '{print > gensub(/ /,"_","g",$3)".csv"}' ex.csv
  • gensub기능적인 것입니다 sub- 작성하기가 약간 더 쉽습니다.
  • >>>이 명령을 실행하기 전에 csv를 생성하지 않는 한 그보다 더 나을 것입니다 .
  • 수백만 개의 서로 다른 3달러 가치가 있다면 문제가 발생할 수 있습니다.

편집하다:새로운 요구사항에 대응(실제로는 새로운 문제)

awk -F, '
  NF == 0     {next}
  !seen[$3]++ {print "Quantity, f..., c..." > gensub(/ /,"_","g",$3)".csv"}
              {print                        > gensub(/ /,"_","g",$3)".csv"}  
' ex.csv

관련 정보