计算两列的差异

计算两列的差异

filename.csv我有一个包含以下内容的CSV 文件。

文件名.csv:

"Afghanistan","94.0","81.1"
"Bahamas","42.9","43.2"
"Bolivia (Plurinational State of)","86.7","31.9"
"Brazil","76.7","0.0"

我想计算两列(第 2 列 - 第 3 列)之间的差异,但得到的输出不正确。其他列中的所有数据都消失了,并且我从减法命令中得到了错误的输出。

我使用的命令:awk '{ print $2 - $3 }' filename.csv

我得到的输出:

0
0
0
0

预期输出文件:

"Afghanistan","94.0","81.1","12.9"
"Bahamas","42.9","43.2","-0.3"
"Bolivia (Plurinational State of)","86.7","31.9","54.8"
"Brazil","76.7","0.0","76.7"

任何帮助表示赞赏。谢谢。

答案1

awk 中的默认分隔符是空格,但 csv 使用引号和逗号,因此 awk 默认情况下会将 csv 文件视为一大列。

另外,您需要去掉引号才能识别数字。因此,您可以使用-F'","'将分隔符更改为用逗号分隔的引用字符串,只要引用的字符串不只包含逗号,这就可以工作。

awk -F'","'  '{ print $2 - $3 }' filename.csv

请注意,您必须引用 shell 的引号。

答案2

这有效:

$ awk 'BEGIN{FS=OFS="\""}{$7=",\""$4-$6"\""}1' filename.csv

输出:

"Afghanistan","94.0","81.1","12.9"
"Bahamas","42.9","43.2","-0.3"
"Bolivia (Plurinational State of)","86.7","31.9","54.8"
"Brazil","76.7","0.0","76.7"

作为旁白,如果数字字段没有被引用,它会简单得多:awk -F, '{$4=$2-$3}1' filename.csv

答案3

使用(以前称为 Perl_6)

raku -MText::CSV -e 'my @a = csv(in => "/Path/To/File");  \
      my @b = @a.map(*.[1]) Z- @a.map(*.[2]); \ 
     .put for @a Z @b;'

#OR

raku -MText::CSV -e 'my @a = csv(in => "/Path/To/File");  \
      .put for @a Z (@a.map(*.[1]) Z- @a.map(*.[2]));' 

输入示例:

"Afghanistan","94.0","81.1"
"Bahamas","42.9","43.2"
"Bolivia (Plurinational State of)","86.7","31.9"
"Brazil","76.7","0.0"

示例输出:

Afghanistan 94.0 81.1 12.9
Bahamas 42.9 43.2 -0.3
Bolivia (Plurinational State of) 86.7 31.9 54.8
Brazil 76.7 0.0 76.7

虽然我确信您可以自行解析 csv(对于小型项目),但在某些时候使用 CSV 解析器可能是有意义的(处理嵌入的引号、嵌入的换行符、检测/更改逗号/非逗号列分隔符、修剪空格等)。

bash您可能会惊讶地发现,在 Raku 编程语言的命令行中调用 CSV 解析器是多么容易。首先使用(module) 命令行标志加载Text::CSV模块,这将为您提供.然后告诉 Raku 期望代码后面带有命令行标志。-M-MText::CSV-e

为了解释第一个示例,@a我们声明了一个数组my并采用 csv 输入。@b声明一个数组my,它采用(零索引)第 1 列和第 2 列之间的差异。这种差异是通过Zzip 元操作符附加减号运算符来实现的,以使Z-。最后,Z使用 zip 元操作符输出原始@acsv,并按列逐行压缩@b

https://github.com/Tux/CSV/blob/master/doc/Text-CSV.pdf(点击下载链接)
https://docs.raku.org/language/operators#index-entry-Z_(zip_metaoperator)
https://raku.org

答案4

使用磨坊主( mlr) 读取无标头 CSV 文件,通过计算第二个和第三个字段之间的差异来创建新的第四个字段,根据标准格式说明符格式化生成的浮点值%g,并输出带引号的 CSV:

$ mlr --csv -N --quote-all put '$4 = fmtnum($2 - $3, "%g")' file
"Afghanistan","94.0","81.1","12.9"
"Bahamas","42.9","43.2","-0.3"
"Bolivia (Plurinational State of)","86.7","31.9","54.8"
"Brazil","76.7","0.0","76.7"

请注意,%g在 Miller 的后续版本中,格式似乎已被破坏,因此您可能需要使用类似的内容%.6g

相关内容