循环遍历bash中的多行CSV行

时间:2016-09-16 11:25:25

标签: bash

我有以下带有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

2 个答案:

答案 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

可以轻松将其转换回原始csv文件
[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方法一样继续。