这里有一个包含标题和分隔符的数据集,如下所示:
a|b|c|d|e|f|g
1|2|3|4|5|6|5
2|4|2|3|5|2|1
另一个具有某些列和值的配置文件,如下所示:
b:5
d:6
我的目的是使用配置文件修改数据集。结果是这样的:
a|b|c|d|e|f|g
1|5|3|6|5|6|5
2|5|2|6|5|2|1
在awk外部不使用“ for”,如何完成此过程?
答案 0 :(得分:4)
使用awk的方法如下:
awk '
NR == FNR { rep[$1] = $2; next }
FNR == 1 { for (i = 1; i <= NF; ++i) if ($i in rep) cols[i] = rep[$i] }
FNR > 1 { for (i in cols) $i = cols[i] }
1
' FS=':' replacements FS='|' OFS='|' dataset
key:value
个替换项保存到数组rep
中
NR == FNR
定位第一个文件(总行号等于该文件的行号)next
跳过脚本的其余部分cols
1
(始终为true)打印第二个文件的所有行,这会触发默认操作{ print }
请注意,由于两个文件具有不同的分隔符,因此将它们指定为awk脚本之后的参数。 FS
定义输入字段分隔符,而OFS
定义下一个文件名参数的输出字段分隔符。参数应读为:
# read the file 'replacements' with input field separator set to ':'
FS=':' replacements
# read the file 'dataset' with input and output field separator set to '|'
FS='|' OFS='|' dataset
$ cat replacements
b:5
d:6
$ cat dataset
a|b|c|d|e|f|g
1|2|3|4|5|6|5
2|4|2|3|5|2|1
$ awk '
> NR == FNR { rep[$1] = $2; next }
> FNR == 1 { for (i = 1; i <= NF; ++i) if ($i in rep) cols[i] = rep[$i] }
> FNR > 1 { for (i in cols) $i = cols[i] }
> 1
> ' FS=':' replacements FS='|' OFS='|' dataset
a|b|c|d|e|f|g
1|5|3|6|5|6|5
2|5|2|6|5|2|1
答案 1 :(得分:1)
按以下顺序进行可能是最明智的选择。首先,您解析配置(假设awk的GNU方言):
gawk -F \| -v OFS=\| 'NR == FNR { # this pattern trigs inside the first file
split($0, mapping, /:/)
rules[mapping[1]] = mapping[2]
next # short-circuit to skip other blocks
}
下一步,在数据文件的第一行,您需要解析列标题:
FNR == 1 {
for(i = 1; i <= NF; ++i) if($i in rules) forcedValues[i] = rules[$i]
print
next
}
现在您有了一个数组forcedValues
,对于从1到7的某些列号(在您的示例中),该数组包含应重置为这些列的值。现在,您将处理文件的其余部分:
{
for(i in forcedValues) $i = forcedValues[i]
print
}' config.txt input.txt > output.txt
(本文中的三个代码段实际上是单个shell命令的一部分,应通过换行符进行连接。)