我有以下名为data
的文件(分隔符是空格,但为了清楚起见,我在这里写了标签):
a b c d e f g
a c d f e
21 18 32 31 35
b a f e d g
12 22 21 28 32 33
...
从第二行开始,我希望通过将包含字母的行与文件的第一行(a b c d e f g
)相匹配来排序每对行,并保留每对字母编号,这样结果是:
a b c d e f g
a b c d e f g
21 0 18 32 35 31 0
a b c d e f g
22 12 0 32 28 21 33
...
请注意,对于每对行,可能会丢失字母,例如在data
示例中,第一对行中有两个缺少的字母,第二对中有一个缺少字母。这些字母在所需的输出中被赋值为零。
到目前为止,我在网站上找到了以下代码:
while read line; do
sorted=$(sort -g -- <<< "${line// /$'\n'}")
printf -- "${sorted//$'\n'/ }\n"
done < data
但它只是按字母或数字顺序对每一行进行排序:
a b c d e f g
a c d e f
18 21 31 32 35
a b d e f g
12 21 22 28 32 33
...
我有没有办法修改代码,以便通过匹配文件的第一行,并保留每对行中的字母对数字来实现?
答案 0 :(得分:2)
Perl救援:
perl -wle '@h = split " ", <>;
print "@h";
until (eof) {
($cols, $vals) = (scalar <>, scalar <>);
my %map;
@map{ split " ", $cols } = split " ", $vals;
print "@h";
print join " ", map $_ // 0, @map{@h};
}' -- data
答案 1 :(得分:0)
在awk中,评论道:
NR == 1 {
# Store reference line in string for simple printing later
ref_str = $0
# Store reference line in array
split($0, ref)
# Number of elements in reference line
nel = NF
print
}
NR > 1 {
# Read letters into array
split($0, keys)
getline
# Create array with letter/number pairs for current line pair
for (i = 1; i <= NF; ++i)
cur_line[keys[i]] = $i
print ref_str
# Loop over elements of reference line
# Insert output field separator, except before first field
# Print value from current line, or 0 if value is not in current line
for (i = 1; i <= nel; ++i)
out = out (i > 1 ? OFS : "") (cur_line[ref[i]] ? cur_line[ref[i]] : 0)
print out
# Delete array for current line; gawk: delete(cur_line)
split("", cur_line)
# Reset output line
out = ""
}
输出以空格分隔:
$ awk -f so.awk infile
a b c d e f g
a b c d e f g
21 0 18 32 35 31 0
a b c d e f g
22 12 0 32 28 21 33
但是,出于验证目的,我们可以将列排成一行:
$ awk -f so.awk infile | column -t
a b c d e f g
a b c d e f g
21 0 18 32 35 31 0
a b c d e f g
22 12 0 32 28 21 33
这是为了清晰而不是简洁而写的。它应该是POSIX awk符合的。
表示文件末尾没有相应数字行的字母行。