我正在编写一个很长的Bash脚本。我想把CSV文件中的单元格读入Bash变量。我可以解析行和第一列,但不能解析其他任何列。以下是我目前的代码:
cat myfile.csv|while read line
do
read -d, col1 col2 < <(echo $line)
echo "I got:$col1|$col2"
done
它只打印第一列。作为附加测试,我尝试了以下操作:read -d, x y < <(echo a,b,)
而$y是空的。所以我试着:read x y < <(echo a b)
而$y是b
,为什么呢?
6条答案
按热度按时间wfsdck301#
您需要使用
IFS
而不是-d
:请注意,对于通用的CSV解析,您应该使用一个专门的工具,它可以处理带有内部逗号的引用字段,以及Bash本身无法处理的其他问题。这样的工具的例子有
cvstool
和csvkit
。ybzsozfc2#
从
man
页面:你使用的是
-d,
,它将在逗号处结束输入行,它不会读取行的其余部分,这就是为什么$y是空的。mu0hgdu03#
如何在Bash中解析CSV文件?
现在讨论这个问题已经晚了,因为bash确实提供了新特性,因为这个问题是关于bash的,而且已经发布的答案都没有显示这种强大而兼容的方法准确地做到了这一点。
正在使用 * 可加载模块 * 解析 *
bash
* 下的CSV文件应拆分为
bash * 可加载 *. C编译的模块。
在bash下,你可以创建、编辑和使用***可加载的c编译模块***。一旦加载,它们就像任何其他***内置***一样工作!!(你可以在source tree上找到更多信息。)
当前的源代码树(2021年10月15日,bash V5.1-rc3)确实包含一系列示例:
在
examples/loadables
目录中有一个完整的 *cvs
* 解析器可供使用:我的天啊!在基于Debian GNU/Linux的系统下,您可能必须通过以下方式安装bash-builtins软件包:
使用 * 可加载bash内置 *:
然后道:
从那里,您可以使用
csv
作为***bash内置***。以我的样:
12,22.45,"Hello, ""man"".","A, b.",42
然后在一个循环中,处理一个文件。
这种方式显然比使用bash内置函数的任何其他组合或对任何二进制文件的fork最快、最强。
不幸的是,根据您的系统实现,如果您的bash版本是在没有
loadable
* 的情况下编译 * 的,这可能不起作用...带有多行CSV字段的完整样本。
这是一个小的示例文件,有1个标题,4列和3行。因为两个字段包含*换行符***,文件长度为6**行。
和一个能够正确解析此文件的小脚本:
这可能导致:(我使用
printf "%q"
将不可打印的字符(如 * newlines *)表示为$'\n'
)您可以在那里找到完整的工作示例:csvsample.sh.txt或csvsample.sh中的一个或多个。
备注:
在这个例子中,我使用 * head line * 来决定 * row width *(列数)。如果你的 * head line * 可以容纳 * newlines *,(或者如果你的CSV使用了不止一个head line)。你必须将number或columns作为参数传递给你的脚本(以及head line的数目)。
警告:
当然,用这个解析CSV并不完美!它可以解析很多简单的CSV文件,但是要注意编码和安全性!!作为示例,这个模块不能处理二进制字段!
仔细阅读csv.c source code comments和RFC 4180!
okxuctiv4#
我们可以用引号括起来的字符串来解析csv文件,并用|使用以下代码
awk
将字符串字段解析为变量,tr
删除引号。由于对每个字段执行
awk
,因此速度稍慢。wnrlj8wa5#
除了来自@Dennis威廉姆森的答案外,当第一行包含CSV的标题时,跳过它可能会有帮助:
vom3gejh6#
如果你想读取CSV文件与一些行,所以这是解决方案。