用Unix方式总结两列

时间:2009-08-28 14:44:00

标签: python perl unix awk brackets

#修复症状

如何有效地总结以下列?

第1栏

1
3
3
...   

第2栏

2323
343
232
...

这应该给我

预期结果

2324
346
235
...

我有两个文件中的列。


#初始情况

我有时会使用太多大括号,以至于我在我的文件中使用了一个{than this}。 我试图找到我使用了一个不必要的花括号的地方。 我在获取数据时使用了以下步骤

查找命令

 find . * -exec grep '{' {} + > /tmp/1
 find . * -exec grep '}' {} + > /tmp/2

AWK命令

 awk -F: '{ print $2 }' /tmp/1 > /tmp/11
 awk -F: '{ print $2 }' /tmp/2 > /tmp/22

该列位于文件/ tmp / 11和/ tmp / 22中。

我在我的程序中重复了很多类似的命令。 这告诉我,这不是正确的方法。

请指教我,如Python,Perl或任何可以减少步骤数量的Unix工具。

6 个答案:

答案 0 :(得分:11)

使用python:

totals = [ int(i)+int(j) for i, j in zip ( open(fname1), open(fname2) ) ]

答案 1 :(得分:11)

如果c1和c2是你的文件,你可以这样做:

$ paste c1 c2 | awk '{print $1 + $2}'

或(没有AWK):

$ paste c1 c2 | while read i j; do echo $(($i+$j)); done

答案 2 :(得分:3)

您可以通过使用同时进行计数和比较的命令来避免中间步骤:

find . -type f -exec perl -nle 'END { print $ARGV if $h{"{"} != $h{"}"} } $h{$_}++ for /([}{])/g' {}\;

每个文件调用一次Perl程序,Perl程序计算每种类型花括号的数量,如果计数不匹配则打印文件名。

您必须小心/([}{]])/部分,如果您说find{}会认为需要在/([{}]])/上进行替换。

警告:如果您尝试针对源代码运行此代码,则此代码会出现误报和否定。请考虑以下情况:

平衡,但用字符串表示:

if ($s eq '{') {
    print "I saw a {\n"
}

不平衡,但是字符串:

while (1) {
   print "}";

您可以使用B::Deparse扩展Perl命令:

perl -MO = Deparse -nle'END {print $ ARGV if $ h {“{”}!= $ h {“}”}} $ h {$ _} ++ for /([} {]) / G'

结果是:

BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    sub END {
        print $ARGV if $h{'{'} != $h{'}'};
    }
    ;
    ++$h{$_} foreach (/([}{])/g);
}

我们现在可以查看该计划的每一部分:

BEGIN { $/ = "\n"; $\ = "\n"; }

这是由-l选项引起的。它将输入和输出记录分隔符设置为“\ n”。这意味着读入的任何内容都将被分成基于“\ n”的记录,并且任何print语句都会附加“\ n”。

LINE: while (defined($_ = <ARGV>)) {
}

这是由-n选项创建的。它遍历通过命令行传入的每个文件(如果没有文件传递则传递给STDIN)读取这些文件的每一行。这也恰好将$ARGV设置为<ARGV>读取的最后一个文件。

chomp $_;

这将删除刚刚读取的行$/变量中的任何内容($_),它在此处没有任何用处。它是由-l选项引起的。

sub END {
    print $ARGV if $h{'{'} != $h{'}'};
}

这是一个END块,此代码将在程序结束时运行。如果存储在与$ARGV%h键相关联的'{'中的值相等,则会打印'}'(上次读取的文件的名称,见上文)。

++$h{$_} foreach (/([}{])/g);

这需要进一步细分:

/
    (    #begin capture
    [}{] #match any of the '}' or '{' characters
    )    #end capture
/gx

是一个正则表达式,它返回匹配的字符串中的“{”和“}”字符列表。由于没有指定字符串,因此将匹配$_变量(保存最后一次从文件中读取的行,见上文)。该列表被输入foreach语句,该语句然后运行列表中每个项目(因此名称)前面的语句。它还将$_(如您所见,$_是Perl中的常用变量)设置为列表中的项目。

++h{$_}

此行将与$_相关联的$ h中的值(将为'{'或'}',见上文)增加一个。

答案 3 :(得分:1)

在Python(或Perl,Awk,&amp; c)中你可以在一个单独的“通行证”中合理地做到这一点 - 我不确定你的意思是“太多大括号”,但你可以肯定会计算每个文件的卷曲使用。例如(除非您不得不担心多GB文件),使用大多数花括号的10个文件:

import heapq
import os
import re

curliest = dict()

for path, dirs, files in os.walk('.'):
  for afile in files:
    fn = os.path.join(path, afile)
    with open(fn) as f:
      data = f.read()
      braces = data.count('{') + data.count('}')
    curliest[fn] = bracs

top10 = heapq.nlargest(10, curlies, curliest.get)
top10.sort(key=curliest.get)
for fn in top10:
  print '%6d %s' % (curliest[fn], fn)

答案 4 :(得分:0)

回复Lutz'n回答

我的问题终于被这个社区解决了

paste -d: /tmp/1 /tmp/2 | awk -F: '{ print $1 "\t" $2 - $4 }'

答案 5 :(得分:0)

只需1个awk命令即可解决您的问题...

awk '{getline i<"file1";print i+$0}'  file2