打印包依赖关系树

时间:2013-05-16 05:10:51

标签: bash recursion awk circular-dependency

使用this file,我想打印一个 给定单个基础包的包依赖关系树。例如,拿走 Bash包

@ bash
# few lines removed
requires: coreutils libintl8 libncursesw10 libreadline7 _update-info-dir cygwin

我希望find-like输出所需的内容 包,部分示例

bash
bash coreutils
bash coreutils libattr1
bash coreutils libattr1 libintl8
bash coreutils libattr1 libintl8 libiconv2
bash coreutils libattr1 libintl8 _autorebase
bash coreutils libattr1 libintl8 _autorebase rebase
bash coreutils libattr1 libintl8 _autorebase rebase dash
bash coreutils libattr1 libintl8 _autorebase rebase dash cygwin
bash coreutils libattr1 libintl8 _autorebase rebase dash cygwin base-cygwin

我有这个命令,但它没有递归

#!awk -f
$1 == "@" {
  pkg = $2
}
$1 == "requires:" {
  for (i=2; i<=NF; i++)
    reqs[pkg][i-1] = $i
}
END {
  query = "bash"
  for (pkg in reqs[query]) {
    print reqs[query][pkg]
  }
}

3 个答案:

答案 0 :(得分:6)

使用Perl并且没有评论:

perl -lne '
  $k = $1 if /@\s*(\S+)/; 
  @r=split(); shift @r; $r{$k} = [@r] if /requires:/;
  END{
    $p = "bash"; @l = ( [$p, 0] );
    while ($p = pop @l) {
        next if $d{$p->[0]}++;
        print " " x $p->[1] . $p->[0];
        for $d(@{$r{$p->[0]}}) {
            push @l, [ $d, $p->[1]+1 ];
        }
    }
  }' setup.ini

Awk版本:

awk '/^@ / { split($0, b); k = b[2]; }
     /^requires: / { a[k] = $0; }
     END {
       p[1] = "bash"; d["bash"] = 0;
       while (length(p)) {
           key = p[length(p)]; depth = d[key]; delete p[length(p)];
           if (!s[key]++) {
               printf "%*s %s\n", depth, "", key;
               split(a[key], r); delete r[1];
               for (req in r) {
                   p[length(p) + 1] = r[req]; d[r[req]] = depth + 1;
               }
           }
       }
     }
' setup.ini

答案 1 :(得分:4)

将GNU awk用于真正的多D数组(但显然​​可以针对其他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

以下是我们需要的新输出格式:

$ 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

答案 2 :(得分:0)

#!/usr/bin/awk -f
@include "join"
$1 == "@" {
  apg = $2
}
$1 == "requires:" {
  for (z=2; z<=NF; z++)
    reqs[apg][z-1] = $z
}
END {
  prpg("bash")
}
function smartmatch(small, large,    values) {
  for (each in large)
    values[large[each]]
  return small in values
}
function prpg(fpg) {
  if (smartmatch(fpg, spath)) return
  spath[length(spath)+1] = fpg
  print join(spath, 1, length(spath))
  if (isarray(reqs[fpg]))
    for (each in reqs[fpg])
      prpg(reqs[fpg][each])
  delete spath[length(spath)]
}

Source