我正在研究一个很长的Bash脚本.我想将CSV文件中的单元格读入Bash变量.我可以解析行和第一列,但不能解析任何其他列.到目前为止,这是我的代码:
cat myfile.csv|while read line
do
read -d, col1 col2 < <(echo $line)
echo "I got:$col1|$col2"
done
Run Code Online (Sandbox Code Playgroud)
它只打印第一列.作为额外的测试,我尝试了以下内容:
read -d, x y < <(echo a,b,)
并且$ y是空的.所以我尝试过:
read x y < <(echo a b)
$ y是b.为什么?
Pau*_*ce. 195
您需要使用IFS而不是-d:
while IFS=, read -r col1 col2
do
echo "I got:$col1|$col2"
done < myfile.csv
Run Code Online (Sandbox Code Playgroud)
请注意,对于通用CSV解析,您应该使用专门的工具来处理带有内部逗号的引用字段,以及Bash无法自行处理的其他问题.这类工具的例子是cvstool和csvkit.
F. *_*uri 19
如何在 Bash 中解析 CSV 文件?
迟到了这个问题,因为bash确实提供了新功能,因为这个问题是关于bash的,而且因为已经发布的答案都没有显示出这种强大且合规的方式来做到这一点。
bash使用可加载模块解析 下的 CSV 文件符合RFC 4180 的字符串,如示例CSV 行:
Run Code Online (Sandbox Code Playgroud)12,22.45,"Hello, ""man"".","A, b.",42
应该被分割为
Run Code Online (Sandbox Code Playgroud)1 12 2 22.45 3 Hello, "man". 4 A, b. 5 42
在bash下,您可以创建、编辑和使用可加载的C编译模块。一旦加载,它们就像任何其他内置的一样工作!(您可以在源树中找到更多信息。;)
当前源代码树(2021 年 10 月 15 日,bash V5.1-rc3)确实包含一堆示例:
12,22.45,"Hello, ""man"".","A, b.",42
Run Code Online (Sandbox Code Playgroud)
目录中有一个完整的工作cvs解析器可供使用examples/loadables:csv.c!
在基于Debian GNU/Linux 的系统下,您可能需要通过以下方式安装bash-builtins软件包
apt install bash-builtins
Run Code Online (Sandbox Code Playgroud)
然后:
enable -f /usr/lib/bash/csv csv
Run Code Online (Sandbox Code Playgroud)
从那里,您可以用作bash 内置csv命令。
以我的样本为例:12,22.45,"Hello, ""man"".","A, b.",42
csv -a myArray '12,22.45,"Hello, ""man"".","A, b.",42'
printf "%s\n" "${myArray[@]}" | cat -n
1 12
2 22.45
3 Hello, "man".
4 A, b.
5 42
Run Code Online (Sandbox Code Playgroud)
然后循环处理一个文件。
while IFS= read -r line;do
csv -a aVar "$line"
printf "First two columns are: [ '%s' - '%s' ]\n" "${aVar[0]}" "${aVar[1]}"
done <myfile.csv
Run Code Online (Sandbox Code Playgroud)
这种方式显然比使用bash内建函数或 fork 任何二进制文件的任何其他组合最快、最强大。
不幸的是,根据您的系统实现,如果您的bash版本是在没有loadable编译的情况下编译的,则这可能不起作用......
符合RFC 4180 的字符串,如以下单个 CSV 行:
Run Code Online (Sandbox Code Playgroud)12,22.45,"Hello ""man"", This is a good day, today!","A, b.",42
应该被分割为
Run Code Online (Sandbox Code Playgroud)1 12 2 22.45 3 Hello "man", This is a good day, today! 4 A, b. 5 42
这是一个小示例文件,包含1 个标题、4列和3行。由于两个字段确实包含换行符,因此文件长度为6行。
1 12
2 22.45
3 Hello, "man".
4 A, b.
5 42
Run Code Online (Sandbox Code Playgroud)
一个小脚本能够正确解析该文件:
#!/bin/bash
enable -f /usr/lib/bash/csv csv
file="sample.csv"
exec {FD}<"$file"
read -ru $FD line
csv -a headline "$line"
printf -v fieldfmt '%-8s: "%%q"\\n' "${headline[@]}"
numcols=${#headline[@]}
while read -ru $FD line;do
while csv -a row "$line" ; (( ${#row[@]} < numcols )) ;do
read -ru $FD sline || break
line+=$'\n'"$sline"
done
printf "$fieldfmt\\n" "${row[@]}"
done
Run Code Online (Sandbox Code Playgroud)
这可能会呈现:(我曾经printf "%q"将不可打印的字符(例如换行符)表示为$'\n')
accept listen for and accept a remote network connection on a given port
asort Sort arrays in-place
basename Return non-directory portion of pathname.
cat cat(1) replacement with no options - the way cat was intended.
csv process one line of csv data and populate an indexed array.
dirname Return directory portion of pathname.
fdflags Change the flag associated with one of bash's open file descriptors.
finfo Print file info.
head Copy first part of files.
hello Obligatory "Hello World" / sample loadable.
...
tee Duplicate standard input.
template Example template for loadable builtin.
truefalse True and false builtins.
tty Return terminal name.
uname Print system information.
unlink Remove a directory entry.
whoami Print out username of current user.
Run Code Online (Sandbox Code Playgroud)
您可以在那里找到完整的工作示例:csvsample.sh.txt或 csvsample.sh。
在此示例中,我使用标题行来确定行宽(列数)。如果您的标题行可以包含换行符(或者如果您的 CSV 使用超过 1 个标题行)。您必须将数字或列作为参数传递给脚本(以及标题行数)。
当然,用这个解析 CSV 并不完美!这适用于许多简单的 CSV 文件,但要关心编码和安全性!例如,该模块将无法处理二进制字段!
仔细阅读csv.c源代码注释和RFC 4180!
特别是如果多行字段位于最后一列,此方法将无法正确循环到第二个引号。
为此,您必须$line在使用csv模块进行解析之前检查引号奇偶性。
我们可以用带引号的字符串解析 csv 文件并用 say | 分隔。使用以下代码
while read -r line
do
field1=$(echo "$line" | awk -F'|' '{printf "%s", $1}' | tr -d '"')
field2=$(echo "$line" | awk -F'|' '{printf "%s", $2}' | tr -d '"')
echo "$field1 $field2"
done < "$csvFile"
Run Code Online (Sandbox Code Playgroud)
awk将字符串字段解析为变量并tr删除引号。
awk为每个字段执行时稍慢。