This is VERY clearly a case for a recursive descent solution:
$ cat tst.awk
function descend(node) {return (map[node] in map ? descend(map[node]) : map[node])}
{ map[$1] = $2 }
END { for (key in map) print key, descend(key) }
$ awk -f tst.awk file
<a> <e>
<b> <e>
<c> <e>
<d> <e>
If infinite recursion in your input is a possibility, here;s an approach that will print as the 2nd field the last node before the recursion starts and put a "*" next to it so you know it's happening:
$ cat tst.awk
function descend(node, child, descendant) {
stack[node]
child = map[node]
if (child in map) {
if (child in stack) {
descendant = node "*"
}
else {
descendant = descend(child)
}
}
else {
descendant = child
}
delete stack[node]
return descendant
}
{ map[$1] = $2 }
END { for (key in map) print key, descend(key) }
.
$ cat file
<w> <w>
<x> <y>
<y> <z>
<z> <x>
<a> <b>
<d> <e>
<b> <c>
<c> <e>
$ awk -f tst.awk file
<w> <w>*
<x> <z>*
<y> <x>*
<z> <y>*
<a> <e>
<b> <e>
<c> <e>
<d> <e>
If you need the output order to match the input order and/or or to print duplicate lines twice, change the bottom 2 lines of the script to:
{ keys[++numKeys] = $1; map[$1] = $2 }
END {
for (keyNr=1; keyNr<=numKeys; keyNr++) {
key = keys[keyNr]
print key, descend(key)
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…