특정 필드를 추출해야 하는 CSV가 있습니다. csv는 파이프로 구분되며( |
) 큰따옴표( "
)는 일부 텍스트에서 텍스트 필드와 줄 바꿈을 보호하는 데 사용됩니다(문제임).
예를 들어.
"aaa"|"111"|"!!!"|""
"bbb"|"222"|"@@
@"|""
"ccc"|"333"|"###"|""
각 레코드의 두 번째 필드를 추출하고 싶습니다.
111
222
333
bash 스크립트를 사용하여 파일을 읽고 있는데 개행 문자가 지정되어 있어도 read
개행 문자에 도달하면 명령이 중지되는 것 같습니다. -d
이는 위의 예에서 내 스크립트가 레코드 1(내가 사용하는 read -d \| varname
)을 올바르게 처리하지만 개행 문자를 세 번째 필드의 일부로 인식하지 못하기 때문에 레코드 2를 올바르게 처리하지 못한다는 것을 의미합니다. 이제 @"|""
새로운 기록으로 간주 되었으므로 모든 지옥이 풀렸습니다.
이 목적 으로 이것을 사용할 수 있습니까 read
? 아니면 대안을 고려해야 합니까?
내가 썼다하늘read
사용하는 설정을 시험해보고 웹을 검색해 보세요. 흥미롭게도 나와 똑같은 입력 파일에 문제가 있는 사람을 만났는데 문제는 Excel에 있었습니다.
답변1
read
CSV를 처리할 수 있는 명령이 내장된 셸의 경우 ksh93
대신 다음을 사용할 수 있습니다 bash
.
$ while IFS='|' read -rS a b c; do printf '%s\n' "$b"; done < file
111
222
333
형식을 처리할 수 있는 형식으로 변환하려면 bash
다음 read
을 수행하세요.
< file ksh93 -c 'while IFS="|" read -rSA a; do
printf "%s|" "${a[@]//[\|]/\\\0}"
printf "\0"
done' |
bash -c 'while IFS="|" read -d "" a b c; do
printf "%s\n" "$b"
done'
답변2
실제로 적합한 CSV 파서를 사용해야 합니다. 예를 들어, 다음과 함께 제공되는 Ruby를 사용합니다.
ruby -rcsv -e 'CSV.foreach("file", :col_sep => "|") {|row| p row; puts row[1]}'
우리는 얻었다
["aaa", "111", "!!!", ""]
111
["bbb", "222", "@@\n@", ""]
222
["ccc", "333", "###", ""]
333
두 번째 줄에 개행 문자가 포함되어 있는 것을 볼 수 있습니다. p row
해당 "디버그" 줄을 제거하려면 제거하세요 .
답변3
좋아요, 그래서 저에게 가장 좋은 해결책은(하지만 취향의 문제인 것 같아요) PHP를 사용하는 것입니다 fgetcsv
. 왜냐하면 저는 이 서버에 이미 PHP가 설치되어 있기 때문입니다. 불행하게도 bash read
명령은 PHP 함수처럼 개행 문자를 처리하지 않습니다. 추가 구분 기호(예: "")를 자동으로 인식합니다.
견본:
<?php
$row = 1;
if (($handle = fopen("test.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 10000, "|")) !== FALSE) {
$num = count($data);
echo "$num fields in line $row:\n";
$row++;
for ($c=0; $c < $num; $c++) {
echo $c + 1 . ": " . $data[$c] . "\n";
}
}
fclose($handle);
}
?>
출력(내 원래 질문과 유사):
4 fields in line 1:
1: aaa
2: 111
3: !!!
4:
4 fields in line 2:
1: bbb
2: 222
3: @@
@
4:
4 fields in line 3:
1: ccc
2: 333
3: ###
4: