- 
      
 - 
        
Save damphat/6214499 to your computer and use it in GitHub Desktop.  
| #! /bin/bash | |
| # Description: show dependency tree | |
| # Author: damphat | |
| if [ $# != 1 ]; then | |
| echo 'Usage: apt-rdepends-tree <package>' | |
| echo 'Required packages: apt-rdepends' | |
| exit 1 | |
| fi | |
| # tree template | |
| T1=" ├─" | |
| T2=" │ ├─" | |
| T3=" │ └─" | |
| # tree template for last node | |
| T4=" └─" | |
| T5=" ├─" | |
| T6=" └─" | |
| # mark '1' for parent node, '2' for child node | |
| TEXT="$(apt-rdepends $1 | sed -e 's/^/1 /' -e 's/.*: /2 /'; echo '-')" | |
| TOTAL=$(echo "$TEXT" | grep '^1' | wc -l) # total parent | |
| COUNT=0 | |
| echo "$TEXT" | while read line; do | |
| tmp=$last | |
| [ "${line:0:1}" != "${last:0:1}" ] && tmp=$(echo $last | sed -e 's/^2/3/') | |
| [ "${tmp:0:1}" == "1" ] && ((COUNT++)) | |
| if [ "$TOTAL" != "$COUNT" ]; then | |
| echo $tmp | sed -e "s/^1/$T1/" -e "s/^2/$T2/" -e "s/^3/$T3/" | |
| else | |
| echo $tmp | sed -e "s/^1/$T4/" -e "s/^2/$T5/" -e "s/^3/$T6/" | |
| fi | |
| last=$line | |
| done | 
+1 very nice! Thanks for writing this and posting on SO!
Would be nice to have an option to suppress (filter out) dependencies which are already listed above, e.g.
    ├─ libexpat1
    │    └─ libc6 (>= 2.4)
    └─ libpcre2-8-0
         └─ libc6 (>= 2.4)
turns into:
    ├─ libexpat1
    │    └─ libc6 (>= 2.4)
    └─ libpcre2-8-0
    If I understand well, actually we only get the tree up to depth 2. It would be cool to get it up to any arbitrary depth.
If I understand well, actually we only get the tree up to depth 2. It would be cool to get it up to any arbitrary depth.
That limitation stems from apt-rdepends output format, as unfortunately it does not nest packages but rather shows each dependency as a top-level package. Fixing this would be non-trivial for such a simple (but amazing) bash script
What an amazing script!
Inspired by this I've created apt-tree, featuring:
- Arbitrary depth, as suggested by @completementgaga , taking care to handle circular dependencies (yes, they exist! See 
libc6) - Suppress duplicate sub-trees, as suggested by @dmak . Packages already printed are marked with 
* - Pass through options to 
apt-rdepends, to allow-r|--reverseas requested by @willemw12 (among many other possibilities) - Full command-line argument parsing, including 
--help 
A small example:
$ apt-tree p7zip-full
Reading package lists... Done
Building dependency tree       
Reading state information... Done
p7zip-full
 ├─ libc6
 │   ╰─ libgcc1
 │       ├─ gcc-8-base
 │       ╰─ libc6*
 ├─ libgcc1*
 ├─ libstdc++6
 │   ├─ gcc-8-base*
 │   ├─ libc6*
 │   ╰─ libgcc1*
 ╰─ p7zip
     ├─ libc6*
     ├─ libgcc1*
     ╰─ libstdc++6*@MestreLion
Hi, Very nice script, thank you. The only missed things we strongly need are:
- Include build-depends for packages, not only Depends
 - Mark somehow those packages which are not available (using apt-cache maybe). For example, if "gcc-8-base" is missed in the local apt repository, then show this something like gcc-8-base (-), those which exist, mark as (+)
 - Print this graph as a plain-text to be able to iterator over it and build each package from the list
 
Will try to implement this by myself. May be you consider implementing this :)
MestreLion Hi, Very nice script, thank you. The only missed things we strongly need are:
Thanks @hiddenman , glad you liked!
Currently I'm unable to dive into this, but I can share a few thoughts about each, it may help:
- Include build-depends for packages, not only Depends
 
Is there a such an option in apt-rdepends? If so, this is possible.
Also, I believe it should either print the build-depends OR the Depends (controllable by a new --build-depends flag), as there are very few (if any) use-cases for a combined list including both. And whoever needs both can always run it twice, with and without the flag.
- Mark somehow those packages which are not available (using apt-cache maybe). For example, if "gcc-8-base" is missed in the local apt repository, then show this something like gcc-8-base (-), those which exist, mark as (+)
 
This might be feasible, possibly best done in parse_deps(). I suggest the mark be (!) for not available, and no mark if available.
- Print this graph as a plain-text to be able to iterator over it and build each package from the list
 
A new --plain flag can easily do that, perhaps using tr -d to remove the UTF (and whitespace?) characters. Indentation can be replaced with TABs, or completely stripped if --no-indent, which would imply --plain.
Will try to implement this by myself. May be you consider implementing this :)
I will. And if you do, it would be amazing if you could open a PR in my repo!!!
(you can also open a new issue there so we can best discuss the above points instead of polluting the this gist)
Inspired by this I've created apt-tree
Inspired by this, I've created apt-tree.sh — not an improvement or rework of apt-tree, but a completely different script written from scratch, which operates on genuine apt-cache directly and doesn't require third-party tools like apt-rdepends.
It features:
- multiple packages support, both from command line and from a file;
 - arbitrary tree depth (automatically stopped when a dependency loop is detected);
 - forward and reverse dependencies;
 - missing packages are marked as such;
 - an option to suppress printing sub-trees already printed before;
 - an option to print a flattened list of all recursive dependencies — as an alternative to hierarchical trees;
 - an option to show the number of direct dependencies of each package;
 - custom tree decoration — prefix, repeating indentation and suffix (plain tabs by default, prefix also applies to list items);
 - adjustable verbosity and progress status — from single-line breadcrumbs up to complete 
apt-cachecommands; - saving output to file will not be cluttered by verbose messages.
 
It also provides built-in help page and extensive documentation with examples.
$ apt-tree.sh -nR udev non-existing-package
non-existing-package (missing!)
udev (4)
	chkconfig (1)
		insserv (0)
	glib (4)
		elfutils (4)
			bzip2 (0)
			flex (0)
			xz (0)
			zlib (0)
		lcc-libs (0)
		libffi (0)
		zlib (0)
	libffi (0)
	usbutils (3)
		libusb (2)
			glibc (0)
			udev (loop!)
		libusb-compat (1)
			libusb (repeating)
		zlib (0)
Comments and suggestions are welcome.
Very nice @blanktonio !!! I've starred you repo, nice to see a solution that does not depend on third-party. Don't forget to include a license so people can use the tool and contribute to it. It can be either a license file, a small header in code (see mine for an example), or at least a paragraph in README. I personally always use a copyleft license (GPLv3), but any FOSS license will do. Thanks and congrats!
this is fantastic! Exactly what I was looking for, thanks a ton :D