如何组合两列中的值?

Sye*_*aib 11 text-processing

我有以下格式的文件:

$ cat /tmp/raw
2015-01   5000   1000
2015-02   6000   2000
2015-03   7000   3000
Run Code Online (Sandbox Code Playgroud)

现在,我想要的是从每行的第 2 列和第 3 列中获取组合值,以便结果如下:

2015-01   6000
2015-02   8000
2015-03   9000
Run Code Online (Sandbox Code Playgroud)

我试过了,但它只显示文件中的最后一个值,如 2015-03 值。

ter*_*don 16

这里有几个方法:

  1. 另一种 awk 方法

    awk '{$2+=$3;}NF--' file
    
    Run Code Online (Sandbox Code Playgroud)
  2. 珀尔

    perl -lane 'print "$F[0] ",$F[1]+$F[2]' file
    
    Run Code Online (Sandbox Code Playgroud)

    或者

    perl -ape 's/$F[1].*/$F[1]+$F[2]/e' file
    
    Run Code Online (Sandbox Code Playgroud)
  3. Shell(比上面的慢得多/效率低得多)

    while read a b c; do echo "$a $((b + c))"; done < file
    
    Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用 `awk '{$2+=$3}NF--'` 这样就不会再有一个空白字段 3 挂了。虽然这只是我的偏好,它太相似了,不能单独作为答案发布:) (3认同)
  • `$2+=$3` 可能更尴尬。 (2认同)

tal*_*zin 11

您可以尝试使用awk

awk '{ print $1, $2 + $3; }' /tmp/raw
Run Code Online (Sandbox Code Playgroud)

结果将是(我认为 2015-03 的值应该是 10000):

2015-01 6000
2015-02 8000
2015-03 10000
Run Code Online (Sandbox Code Playgroud)


mik*_*erv 5

sed 's/[^ ]* */[&]P/;s//&+pc/3'|dc
Run Code Online (Sandbox Code Playgroud)

...印刷...

2015-01   6000
2015-02   8000
2015-03   10000
Run Code Online (Sandbox Code Playgroud)

所以在上面我声明了一个正则表达式,它定义了一个字段范围,它由一个*可变长度的单个字符序列组成,这些字符^不是 <space> ,后面紧跟一个*可变长度的单个字符序列<space>。此声明适用于sed的模式空间,它是一个字符串,\n输入中出现的每个ewline 字符分隔(默认情况下),并且每次出现相同时都会递归替换(默认情况下)下一个。

该声明的接口分为两层,每一层都由至少一个 国际 IEEE 官方标准委员会进行全面监管和指定,以确保sed命令语法的可预测应用。例如,在这种情况下,sed的 API 语法/address/命令(它始终是任何sed s///替换命令的第一个组成部分)一起应用,但是相同的内容被更基本的 API 解释为为regcomp()功能在标准C库

我可以自信地做出这些声明,因为sed不是只是一个程序,而相反,编译后的可执行文件命名sed我的类Unix机器是执行的明确定义,在历史上建立的,与标准控制的sed 应用我的系统的regular-的表达式匹配库。


sed规范:

sed实用程序应支持XBD 基本正则表达式中描述的 BRE ...

...我们在哪里找到...

无论BREs里面和ERES通过在POSIX.1-2008下的系统接口的体积正则表达式匹配的接口支持regcomp()regexec()以及相关的功能。

调用的应用程序regcomp()将向它呈现一个模式字符串和...

...[t]该regcomp()函数应编译模式参数指向的字符串中包含的正则表达式,并将结果放入结构preg ...

为了对此采取行动,所述应用程序将引用regcomp()的伴随功能......

... [T]他regexec()函数比较由指定的空值终止字符串,字符串与正则表达式编译预浸由以前调用初始化regcomp()...

...regexec()应当[一个]阵列的子串的偏移的元素填充字符串对应于\(括号内的子表达式\)图案...图案本身算作一个子表达式...

... [T]他regexec()函数必须在所有填写nmatch的元素pmatch,其中nmatchpmatch由应用程序提供的,即使某些元素pmatch不对应的子表达式的模式


所以当我做...

/[^ ]* */
Run Code Online (Sandbox Code Playgroud)

...sed首先编译正则表达式并将结果存储在内存中,然后将存储在那里的编译自动机应用到我的模式空间的内容中,以满足我的命令所需的次数。每次执行时,结果都是一个或多个空分隔字段的数组,这些字段以 返回的偏移量分隔regexec()

当我这样做...

//
Run Code Online (Sandbox Code Playgroud)

...指示应该使用最近定义的正则表达式,sed可以regexec()再次调用重用预编译的正则表达式,但这次可能将其应用于更改的字符串参数或应用新的nmatch参数作为我的命令。

更具体的还是...

  • s/[^ ]* */[&]P/
    • 用左方括号替换模式空间中第一次出现的模式[,然后是&它本身,然后是]右方括号,后跟一个P字符。
  • s//&+pc/3
    • 再次应用上次使用的正则表达式到当前模式空间,并更换3的第三次出现模式在图案空间&本身,随后所附的字符串+pc

因此,对于sed's input 的每一行,它都会写入其标准输出,给定您的示例数据:

[2015-01   ]P5000   1000+pc
[2015-02   ]P6000   2000+pc
[2015-03   ]P7000   3000+pc
Run Code Online (Sandbox Code Playgroud)

这可能看起来很奇怪,但dc计算器在方括号之间引用其输入中的字符串,并且该P命令将打印堆栈顶部而不附加\newline,然后将其从输入堆栈中弹出。

因此,以第一行为例,dc将执行以下操作:

  • [2015-01 ]P
    • P打印并弹出栈顶
  • 5000
    • 将数字5000压入堆栈顶部,并将当前堆栈中的所有元素(现在没有)向下压一。
  • 1000
    • 同上,但这次主堆栈顶部的数字 5000 被压低 1,并成为堆栈中的第二个元素。
  • +
    • 将堆栈顶部的两个数字相加,将它们从堆栈中弹出并将总和压入堆栈顶部。
    • 这会产生一个仅由数字组成的堆栈6000
    • 如果堆栈顶部的两个元素之一是[字符串,则这是一个语法错误]
  • p
    • print 堆栈的顶部,然后是附加的\newline,而不将其从堆栈中弹出。
  • c
    • c了解堆栈