如何在bash中查找和打印特定字符

Posted

技术标签:

【中文标题】如何在bash中查找和打印特定字符【英文标题】:How to find and print specific character in 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=3A=4,C=5,D=6)。在这种情况下应该输出什么? 【参考方案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); 使用 AB 等初始化 @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@.

【讨论】:

这个解决方案的版本有点不同:***.com/questions/39398986/…

以上是关于如何在bash中查找和打印特定字符的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Bash 中输出粗体文本?

如何在Linux下查找文件内容包含某个特定字符串的文件

Bash 打印,如何

如何在macOS bash脚本中打印框绘图字符

Bash:查找包含特定字符串的文件并将它们复制到文件夹中

使用bash shell脚本从文件中查找和提取特定字符串后的值?