迭代编写程序时已知的字符列表(在本例中,字符为“X”,“Y”,“Z”):
for (i = 1; i <= 3; ++i) {
c = substr("XYZ", i, 1)
# do something with the character
}
问题: 是否有更多awk-y方式执行此操作?请注意,这与this question不同,因为我想要的字符迭代不是输入的一部分。
为了把它放在上下文中,我需要计算X,Y和Z在所有线上一行中特定位置的出现次数。输入应仅包含相同长度的X,Y和Zs:
$ cat input.txt
XYXXXYZZYXY
XXXYYYZYYZY
YZZZZYZZXZZ
XXZXXYYZXZY
$ foo.awk < input.txt
X 3 2 2 2 2 0 0 0 2 1 0
Y 1 1 0 1 1 4 1 1 2 0 3
Z 0 1 2 1 1 0 3 3 0 3 1
目前这是foo.awk
:
#!/bin/awk -f
BEGIN {
FS = ""
}
NR == 1 {
len = NF
}
{
for (i = 1; i <= NF; ++i)
++profile[$i][i]
}
END {
for (c = 1; c <= 3; ++c) {
char = substr("XYZ", c, 1)
printf "%s", char
for (i = 1; i <= len; ++i)
printf " %d", profile[char][i]
printf "\n"
}
}
之前我没有使用过awk,所以可能我的整个方法都是完全错误的。
答案 0 :(得分:3)
你的脚本看起来不错。这是一个版本,说明了风格的一些细微变化:
#!/usr/bin/awk -f
BEGIN {
FS = ""
split("XYZ",chars,"")
}
{
for (i = 1; i <= NF; ++i)
++profile[$i,i]
}
END {
for (c=1;c in chars;c++) {
printf "%s", chars[c]
for (i = 1; i <= NF; ++i)
printf " %d", profile[chars[c],i]
printf "\n"
}
}
语句split("XYZ",chars,"")
创建一个数组chars
,其中包含您的字母。这样,字符可以通过下标来引用。
您的脚本使用多维数组,这是一个GNU扩展。在上面的脚本中,我使用标准awk
方法获得相同的结果。 (设置为FS=""
也是GNU扩展名。)
最后,for
中的外END
循环已更改为使用for (c=1;c in chars;c++) ...
扫描数组索引。即使您更改chars
中的元素数量,这也具有工作的优势。缺点是,除非我们使代码复杂化,否则awk
不能保证索引按顺序出现。