【问题标题】:Extracting particular column name values using sed/ awk/ perl使用 sed/awk/perl 提取特定列名值
【发布时间】:2023-04-10 11:37:01
【问题描述】:

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

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 选项,但我相信还有一种更优雅的方法可以做到这一点。

请帮忙。

【问题讨论】:

    标签: perl sed awk


    【解决方案1】:
    sed 's/[^bd]=[0-9]* *//g'
    

    【讨论】:

      【解决方案2】:
      perl -pe 's/[^bd]=\d+ *//g' data_file
      

      【讨论】:

        【解决方案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
        

        【讨论】:

          【解决方案4】:

          这里是单行版本:

          $ 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

          【讨论】:

          • 这个输出不是他要求的。
          • @rsp 是的,我第一次以某种方式错过了示例输出。现在已经修复了。
          【解决方案5】:

          Sed 会做得很好:

          sed -e 's/[^bd]=[^ ]*//g' -e 's/^ *//' -e 's/ *$//' &lt 文件名

          第一个正则表达式清除不需要的字段(除 b 和 d 之外的所有字段),因此如果您改变主意,可以在此处修改它。另外两个删除前导和尾随空格。

          【讨论】:

            【解决方案6】:

            在 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 解决方案的简短程度——但是修改它以获取更长的字段名称有多容易?似乎正则表达式很快就会变得混乱......无论如何,如果你想使用它,该策略也适用于此。

            【讨论】:

            • ruby -pe 'gsub(/[^bd]=\d+ */, "")' file
            • Ruby 可以做单行 - 即使它不是 lang 最常见或首选的用途:fepus.net/ruby1line.txt
            • 谢谢,Telemachus。我会使用这样的单线,但我发现它们在长期内的用途有限。也就是说,我很乐意将它们用于知道只会使用几次且不需要维护的东西——我倾向于在vim 中使用它们最多(见@ 987654328@)。 (其他人要求的任何东西都倾向于被依赖,所以当你在 3 个月后重新回到它并且无法弄清楚为什么 10 个正则表达式链被破坏时,这很糟糕。我一直在那里用我的代码和其他人的,这并不好玩。)根据提问者的需求,任何一个都可能有用。
            • (由于这个示例输入目前看起来很简单,单行可能是最好的。不过,随着您的继续,事情往往会变得更加复杂......)
            【解决方案7】:

            假设您将来可能想要对这些值执行某些操作,而不仅仅是过滤,您可以以此为基础。

            #! /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";
            }
            

            【讨论】:

            • @Brad 我很高兴其他人也有同样的想法(请参阅我的帖子的第一个版本,该版本在我扩展它时被否决了)。 +1。请注意,您应该使用if defined $kv-&gt;{b},因为0 是允许的值。
            【解决方案8】:

            显然,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 &lt; input

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-11-05
              • 2012-03-06
              • 2011-07-05
              • 1970-01-01
              • 2013-11-11
              • 2012-04-10
              • 2019-08-20
              相关资源
              最近更新 更多