用于在带零或不带零的 CSV 中进行计算的 Bash 脚本

用于在带零或不带零的 CSV 中进行计算的 Bash 脚本

我这里有一个正在使用的脚本。我现在想扩展这一点。

POSIXLY_CORRECT=1 awk -F ';' -v OFS=';' '
  {print $0, NR == 1 ? "Price" : $1 ? $1 : $3 * 1.2}' < file.csv

如果第 1 列中没有零,则用 1.2 计算字段 3 但我想,如果字段 1 为零或什么都没有,则用 1.2 计算字段 3 这可能吗?

这是我的电子表格或 CSV 文件:

Sales Price;External ID;Cost;Internal reference;Name;Sales Description
73;1000-04;141,35;1000-04;Jabra GN 1000 RHL Remote Handset Lifter;Manueller Lifter bzw. Hook-Switch
0;0440-729;61,72;0440-729;Jabra GN 1000 RHL, zbh. für Siemens Optiset; Siemens Optiset Telefone
215;2126-82-04;221,8;2126-82-04;Jabra 2100 Mono QD 3-in-1 Set;Typ: 82 E-STD, Noise-Cancelling Mikrofonarm: Flexibel
0;01.01.8800;11,3;01.01.8800;Jabra Kabel QD -> RJ10 Standard spiral;RJ10

结果应该是这样的

Sales Price;External ID;Cost;Internal reference;Name;Sales Description;Price
73;1000-04;141,35;1000-04;Jabra GN 1000 RHL Remote Handset Lifter;Manueller Lifter bzw. Hook-Switch;73
0;0440-729;61,72;0440-729;Jabra GN 1000 RHL, zbh. für Siemens Optiset; Siemens Optiset Telefone;74,064
215;2126-82-04;221,8;2126-82-04;Jabra 2100 Mono QD 3-in-1 Set;Typ: 82 E-STD, Noise-Cancelling Mikrofonarm: Flexibel;215
0;01.01.8800;11,3;01.01.8800;Jabra Kabel QD -> RJ10 Standard spiral;RJ10;13,56

我现在创建了包含以下内容的 calc.sh:

#!/bin/sh
POSIXLY_CORRECT=1 awk '
    BEGIN { FS=OFS=";" }
    {
        if (NR == 1) val = "Price"
        else         val = ($9 ? $5 * 1.2 : $9)
        print $0, val
    }
' /test.csv

我像这样运行该文件:

calc.sh > /opt/price/result.csv

这是结果:

Sales Price;External ID;Cost;Internal reference;Name;Sales Description
;Price
73;1000-04;141,35;1000-04;Jabra GN 1000 RHL Remote Handset Lifter;Manueller Lifter bzw. Hook-Switch
;
0;0440-729;61,72;0440-729;Jabra GN 1000 RHL, zbh. für Siemens Optiset; Siemens Optiset Telefone
;
215;2126-82-04;221,8;2126-82-04;Jabra 2100 Mono QD 3-in-1 Set;Typ: 82 E-STD, Noise-Cancelling Mikrofonarm: Flexibel
;
0;01.01.8800;11,3;01.01.8800;Jabra Kabel QD -> RJ10 Standard spiral;RJ10;
  1. 价格在第二行。为什么?

  2. 我还可以在某处指定价格应在第 xx 列中输出吗?

答案1

要改变你现有的逻辑:

如果第 1 列没有零,则用 1.2 计算第 3 列

您想要什么:

如果字段 1 为零或无,则用 1.2 计算字段 3

只需改变你所拥有的:

$1 ? $1 : $3 * 1.2

否定条件:

!$1 ? $1 : $3 * 1.2

或交换值的顺序:

$1 ? $3 * 1.2 : $1

交换值的顺序会更好,因为它避免了条件 ,$1 ?部分中的负数和“else”, , 部分中的双重负数: $1

https://en.wikipedia.org/wiki/Ternary_conditional_operator了解如何读取/使用三元表达式。

话虽如此 - 不要嵌套三元表达式,因为这会使您的代码难以阅读,并且始终在三元表达式周围放置括号,以使它们更易于阅读并避免在某些 awks 的某些上下文中出现语法错误(例如,参见https://unix.stackexchange.com/a/588743/133219)。

所以而不是:

{print $0, NR == 1 ? "Price" : $1 ? $3 * 1.2 : $1}

你应该写:

{
    if (NR == 1) val = "Price"
    else         val = ($1 ? $3 * 1.2 : $1)
    print $0, val
}

或类似的。

另外,代替:

awk -F ';' -v OFS=';' 'script'

考虑使用:

awk 'BEGIN{FS=OFS=";"} script'

因此,当您需要 FS 和 OFS 具有相同的值时,您不必在 2 个位置硬编码相同的分隔符 ( ;) - 这使您的代码稍微清晰一些,并且意味着您只需更改 1 个位置(如果/当您决定这样做时)更改分隔符。

我发现您无法理解上述内容,因此为了清楚起见,我建议您的完整脚本应该是:

POSIXLY_CORRECT=1 awk '
    BEGIN { FS=OFS=";" }
    {
        if (NR == 1) val = "Price"
        else         val = ($1 ? $3 * 1.2 : $1)
        print $0, val
    }
' file.csv

https://www.gnu.org/software/gawk/manual/gawk.html#Locale-influences-conversions为什么您需要POSIXLY_CORRECT=1在小数点分隔符,而不是 的区域设置中.

相关内容