【发布时间】:2019-12-03 13:43:54
【问题描述】:
文件/tmp/file.csv 包含以下内容:
name,age,gender
bob,21,m
jane,32,f
CSV 文件将始终具有标题.. 但可能包含不同数量的字段:
id,title,url,description
1,foo name,foo.io,a cool foo site
2,bar title,http://bar.io,a great bar site
3,baz heading,https://baz.io,some description
无论哪种情况,我都想将我的 CSV 数据转换为关联数组的数组..
我需要什么
所以,我想要一个 Bash 4.3 函数,它将 CSV 作为管道输入并将数组发送到标准输出:
/tmp/file.csv:
name,age,gender
bob,21,m
jane,32,f
需要在我的模板系统中使用,像这样:
{{foo | csv_to_array | foo2}}
^ 这是一个固定的 API,我必须使用那个语法。foo2 必须接收数组作为标准输入。
csv_to_array func 必须做它的事情,以便之后我可以这样做:
$ declare -p row1; declare -p row2; declare -p new_array;
它会给我这个:
declare -A row1=([gender]="m" [name]="bob" [age]="21" )
declare -A row2=([gender]="f" [name]="jane" [age]="32" )
declare -a new_array=([0]="row1" [1]="row2")
..一旦我有了这个数组结构(关联数组名称的索引数组),我就有了一个基于 shell 的模板系统来访问它们,如下所示:
{{#new_array}}
Hi {{item.name}}, you are {{item.age}} years old.
{{/new_array}}
但我正在努力生成我需要的数组..
我尝试过的事情:
我已经尝试以此为起点来获取我需要的数组结构:
while IFS=',' read -r -a my_array; do
echo ${my_array[0]} ${my_array[1]} ${my_array[2]}
done <<< $(cat /tmp/file.csv)
..还有这个:
cat /tmp/file.csv | while read line; do
line=( ${line//,/ } )
echo "0: ${line[0]}, 1: ${line[1]}, all: ${line[@]}"
done
(来自https://www.reddit.com/r/commandline/comments/1kym4i/bash_create_array_from_one_line_in_csv/cbu9o2o/)
但我在从另一端得到我想要的东西方面并没有真正取得任何进展......
编辑:
接受了第二个答案,但我不得不破解我正在使用的库以使任一解决方案都能正常工作..
我很乐意查看其他答案,这些答案不会将声明命令导出为字符串,以在当前环境中运行,而是以某种方式提升结果数组对当前环境的声明命令(当前环境是函数运行的地方)。
例子:
$ cat file.csv | csv_to_array
$ declare -p row2 # gives the data
所以,需要明确的是,如果上面的 ^ 在终端中工作,它将在我正在使用的库中工作,而无需添加我必须添加的 hack(其中涉及为^declare -a grepping STDIN 并使用source <(cat); eval $STDIN...在其他功能中)...
有关更多信息,请参阅第二个答案中的我的 cmets。
【问题讨论】:
-
if the above ^ works in a terminal以上将永远不会在任何终端中工作,因为管道的右侧在子外壳内运行。无法从子外壳更改父级环境。您必须使用一些外部实体,例如。一个临时文件来执行此操作,并在您的父 shell 中读取该文件(并删除它)。
标签: arrays bash shell csv associative-array