We all know we can use tree to get a nicely formatted text "visualization" of the structure of a directory; say:

$ tree -spugD /usr/include/boost/accumulators/numeric/
├── [drwxr-xr-x root     root            4096 Dec 19  2011]  detail
│   ├── [-rw-r--r-- root     root            2681 Oct 21  2010]  function1.hpp
│   ├── [-rw-r--r-- root     root             406 Oct 21  2010]  function2.hpp
│   ├── [-rw-r--r-- root     root             409 Oct 21  2010]  function3.hpp
│   ├── [-rw-r--r-- root     root             409 Oct 21  2010]  function4.hpp
│   ├── [-rw-r--r-- root     root            6725 Oct 21  2010]  function_n.hpp
│   └── [-rw-r--r-- root     root             530 Oct 21  2010]  pod_singleton.hpp
├── [drwxr-xr-x root     root            4096 Dec 19  2011]  functional
│   ├── [-rw-r--r-- root     root            2316 Oct 21  2010]  complex.hpp
│   ├── [-rw-r--r-- root     root           16627 Oct 21  2010]  valarray.hpp
│   └── [-rw-r--r-- root     root           12219 Oct 21  2010]  vector.hpp
├── [-rw-r--r-- root     root            9473 Oct 21  2010]  functional_fwd.hpp
└── [-rw-r--r-- root     root           21312 Oct 21  2010]  functional.hpp

2 directories, 11 files

What I would want, is the reverse of this - given a text file with the contents as above save in dirstruct.txt, I could write something like this (pseudo):

$ reverse-tree dirstruct.txt -o /media/destpath

... and so, /media/destpath directory would be created if it doesn't exist, and inside I would get detail subfolder with files function1.hpp, etc; as per the tree above.

Of course, I can always do a copy cp -a and get the same; the idea here would be, that I could change filenames, directory names, sizes, permissions and timestamps in the textfile - and have that reconstructed in the output structure. For files, I first thought I'd be happy with them just being touched (that is, 0 bytes in size) - but it's probably better that the size is reconstructed too - by filling either 0x00 or random bytes, up to the requested size.

Primary use of this would be actually to post questions :) - some of those rely on a directory structure, say from a program I have installed; but the program in itself is irrelevant to the question; then instead of targetting answerers that may happen to have the program installed, I could simply ask a question in respect to an "anonymized" directory tree, which they themselves could quickly reconstruct on their machines, simply by pasting the tree text description in the post.

So - is there a straightforward way to achieve this?

  • 1
    Probably not straightforward, but feasible if someone has the time – LatinSuD Jul 4 '14 at 11:26
  • 1
    It would almost certainly be easier to parse the output of a suitable find command instead of using tree – steeldriver Jul 4 '14 at 12:38
  • 1
    Maybe some idea from this... – user44370 Jul 5 '14 at 11:44

There is no such tool that I've ever seen. You could write a script in a variety of scripting languages, including Bash, to parse the output from tree and reconstruct a corresponding directory on disk that matched it. Looking through the text file would require a while or for loop and making use of mkdir or mkdiir -p to create a directory or a nested directory structure, followed by the use of the touch command to create empty versions of the files in the text file as well.

You could even replicate the timestamps associated since mkdir and touch both offer this as a argument as well if you wanted to get the structure fully replicated.

  • Thanks for that @sim - confirms at least there isn't such tool already existing; cheers! – sdaau Jul 4 '14 at 13:22

As I needed this again, I put together a Perl script that does it; it turned out to be somewhat complicated, so I released it here:

What it does, is that it parses the output from tree - but unlike the OP example, it also needs the --dirsfirst option. To avoid remembering all that, the revrs-tree.pl can be used first like this:

perl revrs-tree.pl --getdir /usr/include/boost/accumulators/ > test.tree

... which will simply call tree with the right options, which outputs to stdout - we capture that in a file test.tree.

Then, we call the same script on the this test.tree content; but the trick is that, the output is not the directories/files themselves - but lines in a bash script instead, printed to stdout. The call looks like this:

perl revrs-tree.pl --zerofill test.tree > test-tree.sh
# alternatively, can receive tree text from stdin:
cat test.tree | perl revrs-tree.pl --zerofill > test-tree.sh

... and test-tree.sh then contains stuff like:

read -p "WARNING! will output in '$RTD' directory!
Press [Enter] key to start output...";
if [ ! -d "$RTD" ] ; then mkdir "$RTD" ; fi ;

mkdir "$TDIR"; sudo chown root:root "$TDIR"; sudo chmod 755 "$TDIR"; sudo touch -d 'Jul 16 2014 9:43:00' "$TDIR";

mkdir "$TDIR"; sudo chown root:root "$TDIR"; sudo chmod 755 "$TDIR"; sudo touch -d 'Jul 16 2014 9:43:00' "$TDIR";

cat /dev/zero | head --bytes 9740 >  "$TFIL";
touch -d 'Oct 21 2010 0:00:00' "$TFIL"; sudo chown root:root "$TFIL"; sudo chmod 644 "$TFIL";

The trick here is:

  • Remember to change the RTD before you run the script - I didn't once, and managed to overwrite /usr/include/boost/accumulators with zero-filled files! (which then required sudo apt-get remove --purge libboost1.42-dev && sudo apt-get install libboost1.42-dev for me) !!! (that is why the script will wait at start for user input) ... Let's say here you've changed it to /tmp/newtarget.
  • tree does not give full timestamps - so times are usually set to 0
  • tree also truncates uids/gids to some 7 or 8 characters - so if you have longer than those, inspect the .sh script, and replace where appropriate.

Then, because it happened the OP example was root owned directory, the .sh script contains sudo at appropriate places, so you might as well call it as super user:

sudo bash test-tree.sh

After a lot of set -x printouts, the script should complete; then you can check whether the directory/file tree structure is reconstructed correctly with, say, diff - or meld:

meld <(tree -spugD /tmp/newtarget/) <(tree -spugD /usr/include/boost/accumulators/)

This gives me no difference in tree output (for this example), apart from the root directory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.