Q:

Visualize tree in bash, like the output of unix "tree"

Given input:
apple: banana eggplant
banana: cantaloupe durian
eggplant:
fig:

I would like to concatenate it into the format:
├─ apple
│  ├─ banana
│  │   ├─ cantaloupe
│  │   └─ durian
│  └─ eggplant
└─ fig

There may or may not be multiple root elements (in the above example, there are two root elements), and I would like to find a solution that handles them without an issue.
Are there any command line tools that can handle this kind of transformation? Failing that, is there anything in other scripting languages that can handle this somewhat easily (I've looked at Python's pprint but I'm not sure how to use it for something like this either)?

A:

following code shall produce the tree structure you are asking for:
branch = '├'
pipe = '|'
end = '└'
dash = '─'

class Tree(object):
    def __init__(self, tag):
        self.tag = tag

class Node(Tree):
    def __init__(self, tag, *nodes):
        super(Node, self).__init__(tag)
        self.nodes = list(nodes)

class Leaf(Tree):
    pass

def _draw_tree(tree, level, last=False, sup=[]):
    def update(left, i):
        if i < len(left):
            left[i] = '   '
        return left

    print ''.join(reduce(update, sup, ['{}  '.format(pipe)] * level)) \
          + (end if last else branch) + '{} '.format(dash) \
          + str(tree.tag)
    if isinstance(tree, Node):
        level += 1
        for node in tree.nodes[:-1]:
            _draw_tree(node, level, sup=sup)
        _draw_tree(tree.nodes[-1], level, True, [level] + sup)

def draw_tree(trees):
    for tree in trees[:-1]:
        _draw_tree(tree, 0)
    _draw_tree(trees[-1], 0, True, [0])

it requires you represent the data using given form.

about your data deserialization, you just need to keep track of the parent nodes, such that when a leaf appears to be a node, you just replace it:
class Track(object):
    def __init__(self, parent, idx):
        self.parent, self.idx = parent, idx

def parser(text):
    trees = []
    tracks = {}
    for line in text.splitlines():
        line = line.strip()
        key, value = map(lambda s: s.strip(), line.split(':', 1))
        nodes = value.split()
        if len(nodes):
            parent = Node(key)
            for i, node in enumerate(nodes):
                tracks[node] = Track(parent, i)
                parent.nodes.append(Leaf(node))
            curnode = parent
            if curnode.tag in tracks:
                t = tracks[curnode.tag]
                t.parent.nodes[t.idx] = curnode
            else:
                trees.append(curnode)
        else:
            curnode = Leaf(key)
            if curnode.tag in tracks:
                # well, how you want to handle it?
                pass # ignore
            else:
                trees.append(curnode)
    return trees

it runs:
>>> text='''apple: banana eggplant
banana: cantaloupe durian
eggplant:
fig:'''
>>> draw_tree(parser(text))
├─ apple
|  ├─ banana
|  |  ├─ cantaloupe
|  |  └─ durian
|  └─ eggplant
└─ fig

hope it fully deals with your problem.

update
my code offers some concern over corner cases, for example:
>>> text='''apple: banana eggplant
banana: cantaloupe durian
eggplant:'''
>>> draw_tree(parser(text))
└─ apple
   ├─ banana
   |  ├─ cantaloupe
   |  └─ durian
   └─ eggplant

notice the left most side of subnodes of apple, there is no | to the end because they are suppressed.
or empty in the middle:
>>> text='''apple: banana
banana: cantaloupe durian
eggplant:'''
>>> draw_tree(parser(text))
├─ apple
|  └─ banana
|     ├─ cantaloupe
|     └─ durian
└─ eggplant

