我想在 zsh 中逐行解析 csv 文件并将其存储在数组中(不带逗号)。是否可以将一行导入到 zsh 中的数组中,然后获取下一行?
问题是我使用的是一个大的 csv 文件,无法快速全部导入。我尝试使用下面的代码:
arr_csv=()
while IFS= read -r line
do
arr_csv+=("$line")
done < import.csv
但由于文件很大,我想读取并存储一行(或访问一行)。
我知道我可以修改代码,这样
arr_csv=()
while IFS= read -r line
do
arr_csv=("$line")
# some modifications
done < import.csv
但如果我想循环该文件,如果我可以使用与 csv 文件中的行相对应的索引会更容易。此外,此方法不会删除分隔行的逗号。
答案1
我想说的是,这需要使用具有 CSV 支持的正确编程语言,例如perl
/ python
... 这里,而不是 shell。
但是,如果您必须使用zsh
并且不介意删除单个单元格中的换行符和回车符,您可以使用 csvkitcsvformat
将 csv 重新格式化为zsh
可以read
更轻松处理的格式:
< file.csv csvformat -SU3 -P'\' |
while IFS=, read -A array; do
typeset array # or anything with $array
done
例如,对于这样的输入:
"foo bar ", "x,y", "blah""blah","new
line"
1,,2,"\\"
其中包括与 csv 相关的典型潜在陷阱的示例,其中给出:
array=( 'foo bar ' x,y 'blah"blah' newline )
array=( 1 '' 2 '\\' )
请注意,缺少-r
soread
会被识别\
为转义字符。不幸的是,虽然用, forcsvformat
转义,但它被解释为行延续而不是转义换行符。<newline>
\<newline>
read
如果您知道输入中从未出现过的两个字符,则可以分别使用它们作为字段分隔符和记录分隔符。例如,可以是 ASCII记录分隔符和单位分隔符控制字符在这里似乎很合适。
us=$'\x1f' rs=$'\x1e'
< file.csv csvformat -SU3 -D$us -M$rs -Q$rs |
while IFS=$us read -rd$rs -A array; do
something with $array
done
这次,在相同的输入上给出:
array=( 'foo bar ' x,y 'blah"blah' $'new\nline' )
array=( 1 '' 2 '\\' )