将 csv 中的许多值四舍五入到小数点后 3 位(printf ?)

将 csv 中的许多值四舍五入到小数点后 3 位(printf ?)

我有一个像这样的粘贴命令 paste -d , file1.csv file2.csv file3.csv

file2.csv 包含这样的数字

0.2
0.3339
0.111111

我希望 file2.csv 中的值具有 3 位小数,如下所示:

0.200
0.334
0.111

对于一个值,这是有效的:

printf "%.3f" "0.3339"->0.334

但对于 file2.csv 中的多个值,这不起作用:

paste -d , file1.csv <(printf %s "%.3f" "$(< file2.csv)") file3.csv

也许有一个好的解决方案?

答案1

有一个名为 的 GNU 实用程序numfmt,它是 GNU coreutils 工具集合的一部分,看起来在这里很有用。它允许您格式化数值,以下命令将file2.csv使用printf格式字符串%.3f(“精度为三位小数的浮点值”)来格式化所有值。格式化的值将打印在标准输出上:

$ numfmt --format=%.3f <file2.csv
0.200
0.334
0.112

正如您所看到的,它默认使用“从零开始”舍入,但这可以通过以下方式更改--round=nearest

$ numfmt --format=%.3f --round=nearest <file2.csv
0.200
0.334
0.111

您可以paste使用进程替换将其插入命令中,如下所示:

paste -d , file1.csv <( numfmt --format=%.3f --round=nearest <file2.csv ) file3.csv

如果您的文件是一个不“简单”的 CSV 文件,即它可能包含带引号的字段,那么您可能需要使用支持 CSV 的工具,例如磨坊主( mlr) 处理数据。下面使用 Miller 表达式中的函数重新创建了numfmt上面的第二个示例(该函数采用格式字符串):fmtnum()putprintf

$ mlr --csv -N put '$1 = fmtnum($1, "%.3f")' file2.csv
0.200
0.334
0.111

--csv选项-N使 Miller 将输入(并写入输出)作为无标头 CSV 读取。

答案2

你很接近;你只需要告诉printf小数点右边的零填充:

$ cat 736678.txt
0.2
0.3339
0.111111
$ for value in $( cat 736678.txt ); do printf "%.3f\n" "$value"; done
0.200
0.334
0.111

格式字符串的%.3f意思是“在该点右侧精确保留三位小数的浮点数”。

答案3

您可以使用它awk来执行所有读取、格式化和粘贴操作:

LC_ALL=C awk '
  {
    getline f2 < "file2.csv"
    getline f3 < "file3.csv"
    printf "%s,%.3f,%s\n", $0, f2, f3
  }' file1.csv

您将在输出中获得与其中一样多的行file1.csv0.000如果文件2 的行数较少,则文件3 的行数为空字符串)。

请注意,当环境中存在变量时,某些 的实现awk(包括 GNU)会在输入和输出时遵循区域设置的十进制基数字符。例如,在法语或德语语言环境中,小数基数字符代替,将被解释为不会被识别并被视为垃圾,并且您将得到输出,从而破坏 CSV 格式。awkPOSIXLY_CORRECT,.1.2e51.2e51,000

因此,LC_ALL=C上面将区域设置固定为C小数基数字符所在的位置.

相关内容