저는 쉘 명령을 처음 사용합니다. 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개의 열이 포함되어 있습니다.
이 데이터 세트에서
- "read"라는 단어가 포함되고 점수가 20보다 큰 줄을 찾습니다. 2. 이 행에서는 점수 값을 기준으로 정렬된 점수 및 ID 열만 인쇄합니다.
- 이러한 정렬된 열을 텍스트 파일에 저장합니다.
예상되는 출력은 다음과 같습니다.
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==1
List에 관심 있는 내용을 인쇄합니다. ....
재미로
열 헤더를 알고 있지만 계산하기에는 너무 게으른 경우...
헤더를 연관 배열에 로드
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