如何在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=3
和A=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);
使用 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@.
【讨论】:
这个解决方案的版本有点不同:***.com/questions/39398986/…以上是关于如何在bash中查找和打印特定字符的主要内容,如果未能解决你的问题,请参考以下文章