CSV 데이터 세트를 필터링하여 행을 찾아 텍스트 파일에 저장

CSV 데이터 세트를 필터링하여 행을 찾아 텍스트 파일에 저장

저는 쉘 명령을 처음 사용합니다. CSV 데이터 세트 fbnews.csv를 기반으로 이 문제에 대해 약간 혼란스럽습니다.

CSV 데이터 세트는 다음과 같습니다.

D,E,F,   message,                 score,    A,B,C,   ID
d,e,f,  Let's read a book,           24,    a,b,c,    1
j,k,l,   Read this book,             39,    d,e,f,    2
m,n,o,   Have you read this book?,   15,    g,h,i,    3

이것은 단지 예일 뿐입니다. 원본 데이터 세트에는 20,000,000개의 행과 20개의 열이 포함되어 있습니다.

이 데이터 세트에서

  1. "read"라는 단어가 포함되고 점수가 20보다 큰 줄을 찾습니다. 2. 이 행에서는 점수 값을 기준으로 정렬된 점수 및 ID 열만 인쇄합니다.
  2. 이러한 정렬된 열을 텍스트 파일에 저장합니다.

예상되는 출력은 다음과 같습니다.

Score   ID
24      1
39      2

쉘 명령을 사용하여 이 작업을 어떻게 수행할 수 있습니까?

답변1

밀러 사용(https://github.com/johnkerl/miller) 그리고

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2
m,n,o,Have you read this book?,15,g,h,i,3

그리고 달리는 중

mlr --csv filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv >output.csv

당신은 할 것

score,ID
24,1
39,2

명령에 대한 몇 가지 세부정보는 다음과 같습니다.

  • --csv,입력 및 출력 형식 설정
  • filter -S '$message=~"(r|R)ead" && $score>20'필터를 적용하세요
  • cut -f score,ID귀하의 분야를 선택하세요

헤더 열보다 셀이 더 많은 잘못된 CSV가 있는 경우

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2,a wrong cell,another wrong cell
m,n,o,Have you read this book?,15,g,h,i,3

ragged옵션을 적용하고 실행할 수 있습니다

mlr --csv --ragged unsparsify then filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv>output.csv

그러나 CSV에 문제가 있는 경우 여기에서 전체 내용을 공유하는 것이 좋습니다.

답변2

나는 배우고 awk있으므로 현명한 분들의 피드백을 기대하고 있습니다.

cat file | tr -s ' ' | awk -F, 'BEGIN { print "Score ID" } tolower($4) ~ /read/ { if($5 >= 20) print $5,$9 }' > output

이 경우 OP 형식을 사용하려면 모든 공백을 하나로 변경하십시오.

tr -s ' '

쉼표를 구분 기호로 사용하세요.

-F,

비교에서 대소문자를 구분하지 않으려면 다음을 수행하십시오.

tolower($4)

네 번째 열에는 "read"라는 문자열이 있습니다.

tolower($4) ~ /read/

다섯 번째 열의 값이 20보다 크거나 같으면 다음을 인쇄합니다.

if($5>=20) print $5,$9

제목 추가(현재 다음을 awk사용하여 이 작업을 수행하려고 합니다.

 BEGIN { print "Score ID" }

산출

score ID
 24  1
 39  2

답변3

나는 쉘 스크립트를 그다지 사용하지 않지만 다른 언어에서도 비슷한 작업을 자주 수행합니다. 검색을 구성하는 데 도움이 되는 몇 가지 사항을 제공하겠습니다.

1 - csv 파일을 구문 분석해야 합니다.

다음 링크에서 csv 파일을 구문 분석하는 방법을 알아볼 수 있습니다. https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash

2 - "read"라는 단어와 일치하는 줄을 가져와야 합니다.

이와 같은 정규식을 사용하고 일부 기준을 조정하여 20.2보다 큰 점수를 캡처할 수 있습니다.

/\b(\w*read\w*)\b/g

표현식에 대한 정보를 보려면 이 사이트에 드롭하세요.https://regexr.com/

3 - 조건에 따라 출력을 정렬해야 합니다.

당신은 그것을 사용할 수 있습니다유형이를 수행하라는 명령입니다. 배열에 할당하고 해당 배열을 정렬하는 것보다 쉽습니다.

4 - 출력 리디렉션

셸 출력을 "script.sh > my_output.txt"와 같은 파일로 쉽게 리디렉션할 수 있습니다. 또는 "var > output.txt" 스크립트에서 이 작업을 수행합니다.

답변4

약간의 awk정규식을 사용한 다음 공백을 정리하기 위한 파이핑column

awk -F',' '{if ( $4 ~ /[Rr]ead/ &&  $5 > 20 || NR==1) print $5, $9}' data.csv | column -t

설명.... 필드 구분 기호를 다음으로 설정한 후,-F','

~....네 번째 필드의 정규 표현식이 "Read" 또는 "read"와 일치하고 &&다섯 번째 필드가 20보다 크거나 ||헤더가 있는 첫 번째 줄에 있는 경우 NR==1List에 관심 있는 내용을 인쇄합니다. ....

재미로

열 헤더를 알고 있지만 계산하기에는 너무 게으른 경우...

헤더를 연관 배열에 로드

declare -A HEADS=( [mess]=mess [id]=ID [score]=score )

..... awk데이터 파일의 첫 번째 행의 열 인덱스를 배열에 넣습니다.

for j in "${!HEADS[@]}"; do HEADS[$j]=$(awk -F',' -v s=${HEADS[$j]} 'NR==1 {for (i=1; i<=NF; ++i) { if ($i ~ s ) print i }}' data.csv) ; done

...맨 위로 돌아가서 awk인덱스를 변수로 주입하세요.

awk -v mess=${HEADS[mess]} -v score=${HEADS[score]} -v id=${HEADS[id]} -F',' '{if ( $mess ~ /[Rr]ead/ &&  $score >20 || NR==1) print $score, $id}' data.csv | column -t

관련 정보