[bash] csv 파일의 한 열을 추출하는 방법

csv 파일이있는 경우 단일 열의 내용 만 인쇄하는 빠른 bash 방법이 있습니까? 각 행에 동일한 수의 열이 있다고 가정하는 것이 안전하지만 각 열의 내용은 길이가 다릅니다.



답변

이를 위해 awk를 사용할 수 있습니다. ‘$ 2’를 원하는 n 번째 열로 변경합니다.

awk -F "\"*,\"*" '{print $2}' textfile.csv


답변

예. cat mycsv.csv | cut -d ',' -f3세 번째 열을 인쇄합니다.


답변

이 작업을 수행 할 수있는 가장 간단한 방법은 csvtool을 사용하는 입니다. csvtool을 사용하는 다른 사용 사례도 있었으며 열 데이터 자체에 나타나는 경우 따옴표 또는 구분 기호를 적절하게 처리 할 수 ​​있습니다.

csvtool format '%(2)\n' input.csv

2를 열 번호로 바꾸면 찾고있는 열 데이터가 효과적으로 추출됩니다.


답변

탭으로 구분 된 파일에서 추출하기 위해 여기에 도착했습니다. 내가 추가 할 것이라고 생각했다.

cat textfile.tsv | cut -f2 -s

여기서 -f20이 아닌 인덱스 열 또는 두 번째 열을 추출합니다.


답변

이 질문에 대한 많은 답변은 훌륭하며 일부는 코너 케이스를 조사했습니다. 일상적으로 사용할 수있는 간단한 답변을 추가하고 싶습니다 … 대부분 그 코너 케이스에 들어가는 경우 (예 : 쉼표 나 쉼표를 따옴표로 이스케이프 처리).

FS (Field Separator)는 값이 공백으로 손상되는 변수입니다. 따라서 기본적으로 awk는 모든 줄의 공간에서 분할됩니다.

따라서 BEGIN (입력하기 전에 실행)을 사용하여이 필드를 원하는대로 설정할 수 있습니다.

awk 'BEGIN {FS = ","}; {print $3}'

위의 코드는 csv 파일의 세 번째 열을 인쇄합니다.


답변

다른 답변은 잘 작동하지만 bash 셸을 사용하여 솔루션을 요청했기 때문에 다음과 같이 할 수 있습니다.

AirBoxOmega:~ d$ cat > file #First we'll create a basic CSV
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10
a,b,c,d,e,f,g,h,i,k
1,2,3,4,5,6,7,8,9,10

그런 다음 다음과 같이 열 (이 예의 첫 번째)을 꺼낼 수 있습니다.

AirBoxOmega:~ d$ while IFS=, read -a csv_line;do echo "${csv_line[0]}";done < file
a
1
a
1
a
1
a
1
a
1
a
1

여기에 몇 가지 일이 있습니다.

  • while IFS=,-이것은 쉼표를 IFS (Internal Field Separator)로 사용하는 것입니다. 쉘이 필드 (텍스트 블록)를 구분하는 것을 알기 위해 사용하는 것입니다. 따라서 IFS =라고 말하는 것은 “a, b”가 “a b”와 동일하다고 말하는 것과 같습니다. IFS = “”(기본값) 인 경우입니다.

  • read -a csv_line; -이것은 한 번에 하나씩 각 줄을 읽고 각 요소를 “csv_line”이라고하는 배열을 만든 다음 while 루프의 “do”섹션으로 보냅니다.

  • do echo "${csv_line[0]}";done < file-이제 우리는 “do”단계에 있으며 “csv_line”배열의 0 번째 요소를 echo합니다. 이 작업은 파일의 모든 줄에서 반복됩니다. < file부분은 어디에서 읽을 수있는 while 루프를 말하고있다. 참고 : bash에서 배열은 인덱스가 0이므로 첫 번째 열은 0 번째 요소입니다.

그래서 거기에 쉘의 CSV에서 열을 가져옵니다. 다른 솔루션은 아마도 더 실용적 일 수 있지만 이것은 순수한 bash입니다.


답변

GNU Awk를 사용할 수 있습니다 . 이 사용자 가이드 문서를 참조하십시오 . 기사 (2015 년 6 월)에 제시된 솔루션의 개선으로, 다음 gawk 명령은 큰 따옴표 필드 안에 큰 따옴표를 허용합니다. 큰 따옴표는 두 개의 연속적인 큰 따옴표 ( “”)로 표시됩니다. 또한 이것은 빈 필드를 허용 하지만 이것조차도 여러 줄 필드를 처리 할 수 ​​없습니다 . 다음 예제 c=3는 textfile.csv 의 세 번째 열 (를 통해 )을 인쇄합니다 .

#!/bin/bash
gawk -- '
BEGIN{
    FPAT="([^,\"]*)|(\"((\"\")*[^\"]*)*\")"
}
{
    if (substr($c, 1, 1) == "\"") {
        $c = substr($c, 2, length($c) - 2) # Get the text within the two quotes
        gsub("\"\"", "\"", $c)  # Normalize double quotes
    }
    print $c
}
' c=3 < <(dos2unix <textfile.csv)

의 사용을주의 dos2unix“\ n”와 UTF-8 (바이트 순서 표시가없는) 각각에 가능한 DOS 스타일의 줄 바꿈을 변환 할 (CRLF 즉 “\ 연구 \ n”) 및 (바이트 순서 마크) UTF-16 인코딩을. 표준 CSV 파일은 CRLF를 줄 바꿈으로 사용 합니다. Wikipedia를 참조하십시오 .

입력에 여러 줄 필드가 포함될 수있는 경우 다음 스크립트를 사용할 수 있습니다. 출력에서 레코드를 분리하기 위해 특수 문자열을 사용하는 것에 유의하십시오 (기본 분리 자 개행이 레코드 내에서 발생할 수 있기 때문입니다). 다시, 다음 예제 c=3는 textfile.csv 의 세 번째 열 (을 통해 )을 인쇄합니다 .

#!/bin/bash
gawk -- '
BEGIN{
    RS="\0" # Read the whole input file as one record;
    # assume there is no null character in input.
    FS="" # Suppose this setting eases internal splitting work.
    ORS="\n####\n" # Use a special output separator to show borders of a record.
}
{
    nof=patsplit($0, a, /([^,"\n]*)|("(("")*[^"]*)*")/, seps)
    field=0;
    for (i=1; i<=nof; i++){
        field++
        if (field==c) {
            if (substr(a[i], 1, 1) == "\"") {
                a[i] = substr(a[i], 2, length(a[i]) - 2) # Get the text within
                # the two quotes.
                gsub(/""/, "\"", a[i])  # Normalize double quotes.
            }
            print a[i]
        }
        if (seps[i]!=",") field=0
    }
}
' c=3 < <(dos2unix <textfile.csv)

문제에 대한 또 다른 접근 방식이 있습니다. csvquote 는 일반적인 Unix 텍스트 처리 도구를 사용하여 특정 열을 선택할 수 있도록 필드 내의 특수 문자가 변환되도록 수정 된 CSV 파일의 내용을 출력 할 수 있습니다. 예를 들어 다음 코드는 세 번째 열을 출력합니다.

csvquote textfile.csv | cut -d ',' -f 3 | csvquote -u

csvquote 임의의 큰 파일을 처리하는 데 사용할 수 있습니다.