我有以下带有3列的csv文件:
row1value1,row1value2,"row1
multi
line
value"
row2value1,row2value2,"row2
multi
line
value"
有没有办法循环遍历它的行(这不起作用,它会读取行):
while read $ROW
do
#some code that uses $ROW variable
done < file.csv
答案 0 :(得分:1)
使用gnu-awk,您可以使用FPAT
:
awk -v RS='"\n' -v FPAT='"[^"]*"|[^,]*' '{
print "Record #", NR, " =======>"
for (i=1; i<=NF; i++) {
sub(/^"/, "", $i)
printf "Field # %d, value=[%s]\n", i, $i
}
}' file.csv
Record # 1 =======>
Field # 1, value=[row1value1]
Field # 2, value=[row1value2]
Field # 3, value=[row1
multi
line
value]
Record # 2 =======>
Field # 1, value=[row2value1]
Field # 2, value=[row2value2]
Field # 3, value=[row2
multi
line
value]
然而,正如我在上面评论的使用PHP的专用CSV解析器,Perl或Python对于这项工作将更加健壮。
答案 1 :(得分:1)
这是一个纯粹的bash解决方案。 multiline_csv.sh
脚本通过用一些替换字符串替换引号之间的换行符来将多行csv转换为标准csv。所以用法是
./multiline_csv.sh CSVFILE SEP
我将您的示例脚本放在名为./multi.csv
的文件中。运行命令./multiline_csv.sh ./multi.csv "\n"
产生以下输出
[ericthewry@eric-arch-pc stackoverflow]$ ./multiline_csv.sh ./multi.csv "\n"
r1c2,r1c2,"row1\nmulti\nline\nvalue"
r2c1,r2c2,"row2\nmultiline\nvalue"
使用printf
:
[ericthewry@eric-arch-pc stackoverflow]$ printf "$(./multiline_csv.sh ./multi.csv "\n")\n"
r1c2,r1c2,"row1
multi
line
value"
r2c1,r2c2,"row2
multiline
value"
这可能是特定于Arch的echo / sprintf的怪癖(我不确定),但您可以使用~~~++??//NEWLINE\\??++~~~
之类的其他分隔符字符串,如果需要,可以sed
。
# multiline_csv.sh
open=0
line_is_open(){
quote="$2"
(printf "$1" | sed -e "s/\(.\)/\1\n/g") | (while read char; do
if [[ "$char" = '"' ]]; then
open=$((($open + 1) % 2))
fi
done && echo $open)
}
cat "$1" | while read ln ; do
flatline="${ln}"
open=$(line_is_open "${ln}" $open)
until [[ "$open" = "0" ]]; do
if read newln
then
flatline="${flatline}$2${newln}"
open=$(line_is_open "${newln}" $open)
else
break
fi
done
echo "${flatline}"
done
完成此翻译后,您可以像通常使用while read $ROW do ... done
方法一样继续。