【问题标题】:How to find and print specific character in bash如何在bash中查找和打印特定字符
【发布时间】:2017-01-12 21:38:54
【问题描述】:

我有类似的文件:

AA,A=14,B=356,C=845,D=4516
BB,A=65,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,F=225

我永远不知道行中是否缺少 A、B、C 或 D 值。但我需要像这样转换这个文件:

AA,A=14,B=356,C=845,D=4516,-,-
BB,A=65,-,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,-,-,F=225

因此,如果缺少任何值,只需打印- 标记。我的计划是具有相同数量的列以便于解析。我更喜欢 awk 解决方案。感谢您的任何建议或帮助。

我的第一次尝试是:

awk '{gsub(/[,]/, "\t")}; BEGIN{ FS = OFS = "\t" } { for(i=1; i<=NF; i++) if($i ~ /^ *$/) $i = "-" }; {print $0}'

但后来我注意到,有些值丢失了。

编辑:

从我的标题中我知道有值 A,B,C,D,E,F...

【问题讨论】:

  • 到目前为止您尝试过什么?通过将, 定义为分隔符并遍历所有列,可以使用 awk..
  • 请参阅已编辑。我的第一次尝试是在 awk 中。
  • 感谢您添加您的尝试,您能否说明您希望输出为tab 分隔还是comma 分隔?
  • 在我的第一次尝试中是制表符分隔的,但我真的不介意。我们可以保留逗号。
  • 如果两列从未同时出现在同一行,则它们的顺序可以是未定义的(例如A=1,B=2,D=3 和A=4,C=5,D=6)。在这种情况下应该输出什么?

标签: bash parsing awk find


【解决方案1】:
$ cat file.txt
AA,A=14,B=356,C=845,D=4516
BB,A=65,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,F=225

$ perl -F, -le '@k=(A..F);
   $op[0]=$F[0]; @op[1..6]=("-")x6;
   $j=0; for($i=1;$i<=$#F;){ if($F[$i] =~ m/$k[$j++]=/){$op[$j]=$F[$i]; $i++} }
   print join(",",@op)
   ' file.txt
AA,A=14,B=356,C=845,D=4516,-,-
BB,A=65,-,C=255,D=841,E=5133,F=1428
CC,A=88,B=54,C=549,-,-,F=225
  • -F, 在, 上拆分输入行并保存到@F 数组中
  • -l 从输入行中删除换行符,在输出中添加换行符
  • @k=(A..F); 使用 A、B 等初始化 @k 数组,直到 F
  • $op[0]=$F[0]; @op[1..6]=("-")x6; 初始化@op 数组,第一个元素为@F,其余六个元素为-
  • for循环遍历@F数组,如果元素与对应索引中的@k数组元素匹配,后跟=,则更改@op元素
  • print join(",",@op) 打印 @op 数组,以 , 作为分隔符

【讨论】:

    【解决方案2】:

    Perl 来救援!

    你还没有指定如何获取header信息,所以在下面的脚本中,直接填充了@header数组。

    %to_idx 哈希将列名映射到它们的索引(A => 0、B => 1 等)。

    每一行都被分成多个字段,每个字段都与预期的字段 ($next) 进行比较,如果需要,还会打印破折号。缺少尾随字段也会发生同样的情况。

    #!/usr/bin/perl
    use warnings;
    use strict;
    
    my @header = qw( A B C D E F );
    
    my %to_idx = map +($header[$_] => $_), 0 .. $#header;
    
    open my $IN, '<', shift or die $!;
    while (<$IN>) {
        chomp;
        my @fields = split /,/;
        print shift @fields;
        my $next = 0;
        for my $field (@fields) {
            my ($name, $value) = split /=/, $field;
            print ',-' x ($to_idx{$name} - $next);
            print ",$name=$value";
            $next = $to_idx{$name} + 1;
        }
        print ',-' x (1 + $#header - $next);  # Missing trailing fields.
        print "\n"
    }
    

    【讨论】:

      【解决方案3】:

      TXR中的解决方案

      @(做 (defstruct 填充缺失 nil 字符串 (hash (hash :equal-based)) (:postinit (自我) (每个((s self.strings)) (设置 [self.hash s] "-"))) (:method add (self str val) (设置 [self.hash str] `@str=@val`)) (:方法打印(自流) (put-string `@{(mapcar self.hash self.strings) ","}` 流)))) @(重复) @ (bind fm @(new fill-missing strings '#"A B C D E F")) @{label},@(coll)@{sym /[^,=]+/}=@{val /[^,]+/}@(do fm.(add sym val))@(end) @ (do (put-line `@label,@fm`)) @(结尾)

      运行:

      $ txr missing.txr 数据 AA,A=14,B=356,C=845,D=4516,-,- BB,A=65,-,C=255,D=841,E=5133,F=1428 CC,A=88,B=54,C=549,-,-,F=225

      【讨论】:

        【解决方案4】:
        BEGIN {                                  
            PROCINFO["sorted_in"]="@ind_str_asc" # order for for(i in a)
            for(i=65;i<=90;i++)                  # create the whole alphabet to array a[]
                a[sprintf("%c", i)]              # you could read the header and use that as well
        }
        {
            split($0,b,",")                      # split record by ","
            printf "%s", b[1]                    # printf first element (AA, BB...)
            delete b[1]                          # get rid of it
            for(i in b) 
                b[substr(b[i],1,1)]=b[i]         # take the first letter to use as index (A=12)
            for(i in a)                          # go thru alphabet and printf from b[]
                printf "%s%s", OFS, (i in b?b[i]:"-"); print ""
        }
        
        awk -v OFS=\, -f parsing.awk tbparsed.txt
        AA,A=14,B=356,C=845,D=4516,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-
        BB,A=65,-,C=255,D=841,E=5133,F=1428,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-
        CC,A=88,B=54,C=549,-,-,F=225,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-,-
        

        它为记录中未找到的每个字母打印“-”。如果数据有标题,您可以将split 转换为二维数组b[NR] 并将for(i in a) 更改为for(i in b[1]) ... printf ... b[NR][b[1][i]] ...,如果您不需要静态第一列,请删除第一个printf 和@ 987654328@.

        【讨论】:

        猜你喜欢
        • 2021-12-22
        • 2018-03-16
        • 2016-03-12
        • 1970-01-01
        • 1970-01-01
        • 2018-03-21
        • 1970-01-01
        • 2021-12-06
        • 2019-03-30
        相关资源
        最近更新 更多