我正在尝试构建一个 awk 语句来读取此文件:
A 1,2,3 *
A 4,5,6 **
B 1
B 4,5 *
并构建一个像这样的文件:
A 1,2,3 * 3 1 0.333
A 4,5,6 ** 3 2 0.666
B 1 1 0 0
B 4,5 * 2 1 0.5
在这个新文件中,前三列与原始文件中的相同。第四列必须包含第 2 列中逗号分隔元素的数量。第五列必须包含第 3 列中的字符数量。最后一列包含第 5 列在第 4 列中的比例(即第 5 列除以第 4 列) )。
我正在尝试以下代码:
awk '{print $1"\t"$2"\t"$3"\t"(NF","$2 -1)"\t"length($3)"\t"(length($3)/(NF","$2-1))}' file1 > file2
但我得到以下输出:
A 1,2,3 * 3,0 1 0.333333
A 4,5,6 ** 3,3 2 0.666667
B 1 2,0 0 0
B 4,5 * 3,3 1 0.333333
我不明白我在第 4 列做错了什么。
答案1
您似乎希望(NF","$2 -1)
将其视为一个函数,该函数将返回字段中逗号分隔元素的数量$2
- 但它不会。NF
始终是字段的数量记录。
相反,您可以使用 awk 的split
函数split($2,a,",")
将字段拆分$2
为数组a
并返回元素数量。您还可以通过将输出字段分隔符设置为制表符来整理代码,而不是在打印语句中使用显式的“\t”
awk '{l2=split($2,a,","); OFS="\t"; print $1, $2, $3, l2, length($3), length($3)/l2}' file1
答案2
这是 Perl 方法:
$ perl -lane '@k=($F[1]=~/,/g); $i=$#k+2; $l=length($F[2]);
print "@F $i $l ", $l/$i' file
A 1,2,3 * 3 1 0.333333333333333
A 4,5,6 ** 3 2 0.666666666666667
B 1 1 0
B 4,5 * 2 1 0.5
或者,使用printf
漂亮的格式:
$ perl -lane '@k=($F[1]=~/,/g); $i=$#k+2; $l=length($F[2]);
printf "%s %-5s %-3s %s %3s %10f\n",@F,$i,$l,$l/$i' file
A 1,2,3 * 3 1 0.333333
A 4,5,6 ** 3 2 0.666667
B 1 1 0 0.000000
B 4,5 * 2 1 0.500000
解释
-lane
:-l
从每个输入行中删除尾随换行符;自动-a
将每个输入行拆分到空格上的数组中@F
;意思-n
是“逐行读取输入文件”,并且-e
允许您将脚本作为命令行参数传递。@k=($F[1]=~/,/g); $i=$#k+2;
:数组@k
包含第二个字段中找到的所有逗号。然后,$i
设置最大索引为@F
($#F
)加二。需要加 2,因为 i) 数组是从 0 开始计数的,因此单元素数组的最大索引将为 0。我们计算的是逗号,而不是值,因此我们需要再加 1,因为1,2
有两个值,但只有一个值逗号。$l=length($F[2]);
:$l
现在是 3d 字段的字符数。print "@F $i $l ", $l/$i
:打印所请求的信息。@F
是输入文件中的行,其余的是您所要求的。