source

Bash에서 CSV 파일을 해석하는 방법

ittop 2023. 4. 22. 10:28
반응형

Bash에서 CSV 파일을 해석하는 방법

긴 Bash 대본을 쓰고 있어요.CSV 파일에서 Bash 변수로 셀을 읽고 싶다.행과 첫 번째 열은 구문 분석할 수 있지만 다른 열은 구문 분석할 수 없습니다.지금까지의 코드는 다음과 같습니다.


  cat myfile.csv|while read line
  do
    read -d, col1 col2 < <(echo $line)
    echo "I got:$col1|$col2"
  done

첫 번째 열만 인쇄하는 거야추가 테스트로 다음을 시도했습니다.

read -d, x y < <(echo a,b,)

그리고 $y는 비어있다.그래서 나는 시도했다:

read x y < <(echo a b)

그리고 $y는b.왜요?

를 사용해야 합니다.IFS대신-d:

while IFS=, read -r col1 col2
do
    echo "I got:$col1|$col2"
done < myfile.csv

지정된 수의 헤더 행을 건너뛰려면 다음 절차를 수행합니다.

skip_headers=3
while IFS=, read -r col1 col2
do
    if ((skip_headers))
    then
        ((skip_headers--))
    else
        echo "I got:$col1|$col2"
    fi
done < myfile.csv

CSV의 일반적인 해석에서는 내부 콤마를 사용하여 따옴표로 둘러싸인 필드를 처리할 수 있는 특수한 도구를 사용해야 합니다.또한 Bash가 단독으로 처리할 수 없는 문제도 있습니다.이러한 툴의 예는 및 입니다.

Bash에서 CSV 파일을 해석하는 방법

이 질문에 늦게 하면 bash와 로 새로운 기능이 제공됩니다.이 질문은 bash에 관한 것으로, 이미 투고된 답변 중 이 강력하고 준거한 방법을 정확하게 나타내는 것이 없기 때문입니다.

로딩 가능한 모듈을 사용한에서의 CSV 파일 해석

RFC 4180준거문자열은 다음과 같습니다.

12,22.45,"Hello, ""man"".","A, b.",42

로서 분할되어야 한다.

1  12
2  22.45
3  Hello, "man".
4  A, b.
5  42

bash 로드 가능.C 컴파일된 모듈

에서 로드 한 c 컴파일모듈을 작성, 편집 및 사용할 수 있습니다.로딩이 완료되면 다른 빌트인과 동일하게 동작합니다!!(자세한 내용은 소스 트리에서 확인할 수 있습니다.;)

현재 소스 트리(10월 15일 2021, bash V5.1-rc3)에는 샘플이 다수 포함되어 있습니다.

accept        listen for and accept a remote network connection on a given port
asort         Sort arrays in-place
basename      Return non-directory portion of pathname.
cat           cat(1) replacement with no options - the way cat was intended.
csv           process one line of csv data and populate an indexed array.
dirname       Return directory portion of pathname.
fdflags       Change the flag associated with one of bash's open file descriptors.
finfo         Print file info.
head          Copy first part of files.
hello         Obligatory "Hello World" / sample loadable.
...
tee           Duplicate standard input.
template      Example template for loadable builtin.
truefalse     True and false builtins.
tty           Return terminal name.
uname         Print system information.
unlink        Remove a directory entry.
whoami        Print out username of current user.

에서 사용할 수 있는 완전한 동작 파서가 준비되어 있습니다.examples/loadables디렉토리: csv.c!!

Debian GNU/Linux 기반 시스템에서는 다음 방법으로 bash-builtins 패키지를 설치해야 할 수 있습니다.

apt install bash-builtins

로드 가능한 bash-builtin 사용:

그 후, 다음과 같이 입력합니다.

enable -f /usr/lib/bash/csv csv

거기서부터,csv배쉬가 내장되어 있습니다.

샘플 사용 시:12,22.45,"Hello, ""man"".","A, b.",42

csv -a myArray '12,22.45,"Hello, ""man"".","A, b.",42'
printf "%s\n" "${myArray[@]}" | cat -n
     1      12
     2      22.45
     3      Hello, "man".
     4      A, b.
     5      42

그리고 루프에서 파일을 처리합니다.

while IFS= read -r line;do
    csv -a aVar "$line"
    printf "First two columns are: [ '%s' - '%s' ]\n" "${aVar[0]}" "${aVar[1]}"
done <myfile.csv

이 방법은 bash builtins fork를 바이너리에 조합하여 사용하는 것보다 분명 가장 빠르고 강력합니다.

안타깝게도 시스템 구현에 따라서는 bash 이 없이 컴파일된 경우 이 기능이 작동하지 않을 수 있습니다.

여러 줄의 CSV 필드를 사용한 완전한 샘플.

RFC 4180준거문자열은 다음과 같습니다.

12,22.45,"Hello ""man"",
This is a good day, today!","A, b.",42

로서 분할되어야 한다.

1  12
2  22.45
3  Hello "man",
   This is a good day, today!
4  A, b.
5  42

여러 줄 필드가 포함된 CSV를 해석하기 위한 전체 샘플 스크립트

제목 1개, 4개, 3개가 있는 작은 샘플 파일입니다.두 필드에는 줄바꿈이 포함되어 있으므로 파일의 길이는 6줄입니다.

Id,Name,Desc,Value
1234,Cpt1023,"Energy counter",34213
2343,Sns2123,"Temperatur sensor
to trigg for alarm",48.4
42,Eye1412,"Solar sensor ""Day /
Night""",12199.21

이 파일을 올바르게 해석할 수 있는 작은 스크립트:

#!/bin/bash

enable -f /usr/lib/bash/csv csv

file="sample.csv"
exec {FD}<"$file"

read -ru $FD line
csv -a headline "$line"
printf -v fieldfmt '%-8s: "%%q"\\n' "${headline[@]}"
numcols=${#headline[@]}

while read -ru $FD line;do
    while csv -a row "$line" ; (( ${#row[@]} < numcols )) ;do
        read -ru $FD sline || break
        line+=$'\n'"$sline"
    done
    printf "$fieldfmt\\n" "${row[@]}"
done

은 다음과 같이 나타낼 수 (이미 사용하였습니다.)printf "%q" 바꿈과 같은 인쇄 불가능한 문자를 표시하다$'\n')

Id      : "1234"
Name    : "Cpt1023"
Desc    : "Energy\ counter"
Value   : "34213"

Id      : "2343"
Name    : "Sns2123"
Desc    : "$'Temperatur sensor\nto trigg for alarm'"
Value   : "48.4"

Id      : "42"
Name    : "Eye1412"
Desc    : "$'Solar sensor "Day /\nNight"'"
Value   : "12199.21"

csvsample.sh.txt 또는 csvsample.sh에서 완전한 작업 샘플을 찾을 수 있습니다.

주의:

이 예제에서는 헤드라인을 사용하여 너비(열 수)를 결정합니다.헤드라인에서 새로운 회선을 유지할 수 있는 경우(또는 CSV에서 헤드라인을 여러 개 사용하는 경우)스크립트에 인수(및 헤드라인 수)로 숫자 또는 열을 전달해야 합니다.

경고:

물론 이를 사용하여 CSV를 해석하는 것은 완벽하지 않습니다!이것은 많은 단순한 CSV 파일에 대응하지만 인코딩과 보안에 유의하십시오!!샘플의 경우 이 모듈은 이진 필드를 처리할 수 없습니다.

csv.c 소스 코드코멘트와 RFC 4180을 주의 깊게 읽어 주세요.

man 링크:

d delimate : delimate의 첫 번째 문자는 줄바꿈이 아닌 입력 행을 종료하기 위해 사용됩니다.

사용하고 있습니다.-d,콤마의 입력 행을 종료합니다.이치노가가 、 $y 、 yy 。

따옴표로 묶은 문자열로 CSV 파일을 해석하고 다음 코드를 사용하여 say |로 구분할 수 있습니다.

while read -r line
do
    field1=$(echo "$line" | awk -F'|' '{printf "%s", $1}' | tr -d '"')
    field2=$(echo "$line" | awk -F'|' '{printf "%s", $2}' | tr -d '"')

    echo "$field1 $field2"
done < "$csvFile"

awk 및 "변수"로합니다.tr따옴표를 삭제합니다.

awk각 필드에 대해 실행됩니다.

@Dennis Williamson의 응답 외에 CSV 헤더가 포함되어 있는 경우는 첫 번째 행을 건너뛰는 것이 도움이 될 수 있습니다.

{
  read
  while IFS=, read -r col1 col2
  do
    echo "I got:$col1|$col2"
  done 
} < myfile.csv

몇 줄의 CSV 파일을 읽는 경우는, 이것이 해결책입니다.

while IFS=, read -ra line
do 
    test $i -eq 1 && ((i=i+1)) && continue
    for col_val in ${line[@]}
    do
        echo -n "$col_val|"                 
    done
    echo        
done < "$csvFile"

언급URL : https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash

반응형