2016-09-16 67 views
0

我有3列以下csv文件:循環通過多CSV排在bash

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

使用PGP,Python,Perl等可用的CVS解析器 – anubhava

+0

我知道有可用的解決方案,但我試圖找出這是否可能在bash中。 –

回答

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] 

然而,正如我評論ABO使用PHP,Perl或Python的專用CSV解析器對於這項工作將更加強大。

1

這是純粹的bash解決方案。 multiline_csv.sh腳本通過用一些替換字符串替換引號之間的換行符來將多行csv轉換爲標準csv。所以用法是

./multiline_csv.sh CSVFILE SEP

我把你的示例腳本在名爲./multi.csv文件。運行命令./multiline_csv.sh ./multi.csv "\n"產生以下輸出

[[email protected] stackoverflow]$ ./multiline_csv.sh ./multi.csv "\n" 
r1c2,r1c2,"row1\nmulti\nline\nvalue" 
r2c1,r2c2,"row2\nmultiline\nvalue" 

這可以使用printf很容易地轉換回原來的CSV文件:

[[email protected] stackoverflow]$ printf "$(./multiline_csv.sh ./multi.csv "\n")\n" 
r1c2,r1c2,"row1 
multi 
line 
value" 
r2c1,r2c2,"row2 
multiline 
value" 

這可能是回聲/的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方法。