使用sed / awk / perl提取特定的列名值

时间:2009-10-27 13:11:54

标签: perl sed awk

我有一个输入文件,例如:

a=1 b=2 c=3 d=4
a=2 b=3
a=0 c=7
a=3 b=9 c=0 d=5
a=4 d=1
c=9

假设列名(a,b,c和d)的顺序保持不变。如何编写脚本/命令来帮助我提取特定于列b和d的值?所以我的输出应该是:

b=2 d=4
b=3

b=9 d=5
d=1

我可以使用多个分隔符来编写一个“不那么好”的awk命令,使用管道来过滤这些分隔符以使用-F选项,但我相信还有更优雅的方法来执行此操作。

请帮助。

8 个答案:

答案 0 :(得分:5)

sed 's/[^bd]=[0-9]* *//g'

答案 1 :(得分:3)

perl -pe 's/[^bd]=\d+ *//g' data_file

答案 2 :(得分:3)

# awk '{ for(i=1;i<=NF;i++){if($i~/(b|d)=/){printf $i" "} }print ""}' file
b=2 d=4
b=3

b=9 d=5
d=1

答案 3 :(得分:2)

以下是单行版本:

$ perl -lpe '@x=/([bd]=[0-9])/g; $_="@x"' test.txt
列表上下文中的

m//g将所有匹配作为列表返回。

#!/usr/bin/perl
use strict; use warnings;

while ( <DATA> ) {
    if( my @cols = /([bd]=[0-9])/g ) {
        print "@cols";
    }
    print "\n";
}

__DATA__
a=1 b=2 c=3 d=4
a=2 b=3
a=0 c=7
a=3 b=9 c=0 d=5
a=4 d=1
c=9

输出:

C:\Temp> t.pl
b=2 d=4
b=3

b=9 d=5
d=1

答案 4 :(得分:1)

Sed会做得非常好:

sed -e 's/[^bd]=[^ ]*//g' -e 's/^ *//' -e 's/ *$//' < filename

第一个正则表达式清除了不需要的字段(除了b和d之外的所有字符),所以如果你改变主意,那就是修改它的地方。另外两个删除前导和尾随空格。

答案 5 :(得分:1)

在Ruby中:

#!/usr/bin/env ruby
filename = ARGV[0]
fields = ARGV[1..ARGV.length]

File.open(filename) do |file|
  file.each_line do |line|
    pairs = line.split(' ').map { |expression| expression.split('=') }
    value_hash = Hash[pairs]

    requested_fields = []

    fields.each do |field|
      requested_fields << "#{field}=#{value_hash[field]}" unless value_hash[field].nil?
    end

    puts requested_fields.join(' ')
  end
end

使用ruby ruby_script_name.rb input_file.txt field1 field2拨打电话。

我喜欢sed / perl解决方案的简短程度 - 但是如何轻松修改它以获取更长的字段名称?好像正则表达式会很快变得混乱......无论如何,如果你想使用它,那么这个策略也适用于此。

答案 6 :(得分:1)

假设您可能希望将来对某些值进行操作,除了过滤之外,您可以将其作为基础。

#! /usr/bin/env perl
use warnings;
use strict;

my @lines;

while(<>){
  my %kv = /([a-z])=([0-9])/ig;
  push @lines, \%kv;
}

for my $kv (@lines){
  # $kv->{a} ||= 1;
  # next unless $kv->{c};

  print "b=$kv->{b} " if defined $kv->{b};
  print "b=$kv->{d} " if defined $kv->{d};
  print "\n";
}

答案 7 :(得分:0)

显然,PostScript是最好的选择...... XD

(%stdin) (r) file
{
    dup 100 string readline not {exit} if
    {
        dup () eq {pop exit} if
        token pop 3 string cvs
        dup 0 get << 98 / 100 / >> exch known
        {print ( ) print} {pop} ifelse
    } loop
    / =
} loop

用法:gs -q -dNOPROMPT -dNODISPLAY -dBATCH thisfile.ps < input

注意:将<< 98 / 100 / >>替换为适当的ASCII值(98 = b,100 = d),每个值后跟一个以空格分隔的斜杠(尽管您不必使用斜杠;它只是一个虚拟对象)。例如,要选择“c”,“e”和“f”,请使用<< 99 / 101 / 102 / >>

每行最多100个字符;如果你的行更长,请用更大的数字替换100 string。同样,如果您的3 string条目超过三个字符,请替换x=#。但是,如果x不止一个字符,则不起作用。