Using GNU awk for true multidimensional arrays (but, obviously, can be changed for other awks):
$ cat tst.awk /^@/ { pkg = $2 } /^requires:/ { for (i=2;i<=NF;i++) reqs[pkg][$i] } END { prtPkg(root) } function prtPkg(pkg, req) { if (!seen[pkg]++) { printf "%*s%s\n", indent, "", pkg indent += 2 if (pkg in reqs) for (req in reqs[pkg]) prtPkg(req) indent -= 2 } }
.
$ cat file3 @ bash whatever requires: libgcc1 libintl8 libncursesw10 libreadline7 _update-info-dir @ libintl8 whatever requires: libiconv2 bash common @ libgcc1 whatever requires: _autorebase common
.
$ awk -v root="bash" -f tst.awk file3 bash libncursesw10 libgcc1 _autorebase common _update-info-dir libreadline7 libintl8 libiconv2
Here is what we need for the new output format you want:
$ cat file3 @ bash requires: libgcc1 libintl8 libncursesw10 libreadline7 @ libncursesw10 requires: libgcc1 libstdc++6 terminfo libreadline7
.
$ cat tst.awk /^@/ { pkg = $2 } /^requires:/ { for (i=2;i<=NF;i++) reqs[pkg][i-1]=$i } END { setMinDepth(root); prtPkg(root) } function setMinDepth(pkg, req, i) { depth++ minDepth[pkg] = ( !(pkg in minDepth) || (depth < minDepth[pkg]) ? depth : minDepth[pkg]) if (depth == minDepth[pkg]) { if (pkg in reqs) for (i=1; i in reqs[pkg]; i++) { req = reqs[pkg][i] setMinDepth(req) } } depth-- } function prtPkg(pkg, req, i) { depth++ if ( (depth == minDepth[pkg]) && (!seen[pkg]++) ) { printf "%*s%s\n", indent, "", pkg indent += 2 if (pkg in reqs) for (i=1; i in reqs[pkg]; i++) { req = reqs[pkg][i] prtPkg(req) } indent -= 2 } depth-- }
.
$ awk -v root="bash" -f tst.awk file3 bash libgcc1 libintl8 libncursesw10 libstdc++6 terminfo libreadline7
source share