0

Executing the tree command in Windows CMD will give me some output like this:

C:\DIR1
│   foo.txt
│
└───dir2
        bar.txt

How can I append trailing slashes to directories to make it clearer that they aren't files? It should apply to both the root directory and subdirectories, like this:

C:\DIR1\
│   foo.txt
│
└───dir2\
        bar.txt

1 Answer 1

0

Overview

One solution is to use a Python script to wrap the tree command and add a trailing \ at the end of every directory that way.

This script below is intended for Python 3.x. If you decide to use this script, you'll likely want to install Python at the command line for ease of use, as well as associate .py files with Python.


Caveats

  • Wrapping the tree command makes it slightly slower (due to script execution time). That said, this difference is likely minimal enough to be ignored in most instances.

  • Every effort has been made to reproduce the output of tree as closely as possible (so that there should effectively be no difference between tree and this script, minus the added \). However, it is theoretically possible you may encounter some unknown issues with the output, dependent on your use-case.

  • One issue you may encounter is outputting to a text file. This script will crash if /A isn't specified. tree is more graceful in that it simply writes the "wrong" characters.

  • One small issue that may occur is that it's technically possible to have a "false positive" on any item that contains +--- as part of its name (assuming that item isn't a directory) when using ASCII (/A) output mode.

  • Use \\ (not just \) if specifying a full path for the root_dir variable (below).

  • The implementation of /F and /A at the command line is intentionally minimalist. If you want something more robust, you should look at argparse (or just read tree /?).

  • This script was made with Windows 7 and code pages cp1252 and cp437 in mind. You may need to change these encoding values depending on where you live, etc.


Script

Notes

When tree is run, it uses either three extended pipe symbols (───) or three hyphens (---) to preface directory names. This script looks for lines containing those values and adds \ to the end of those lines, as appropriate.

You can set default script options with the initial show_files and ascii_tree values. Command line options can be e.g. bonsai.py, bonsai.py /F, bonsai.py /A or bonsai.py /F /A, respectively.

As written, root_dir is hard-coded into the script (i.e. it doesn't have an option to be set from the command line).

ex. bonsai.py:

# Wrapper for the Windows "tree" command, which adds a "\" to the end of
# directory names to more easily distinguish them from files.

# https://docs.python.org/3/library/subprocess.html
# https://docs.python.org/3/library/sys.html

# --- Imports ---

import subprocess
import sys

# --- Switches ---

# Select "tree" "/F" and "/A" options. "/F" displays files under directory
# listings and "/A" controls ASCII output (i.e. no extended characters).

# These should only ever be "True" or "False".
show_files = False
ascii_tree = False

# Command line options
if '/F' in sys.argv:
    show_files = True

if '/A' in sys.argv:
    ascii_tree = True

options = ''

if show_files is True:
    options += ' /F'

if ascii_tree is True:
    options += ' /A'

# --- Variables ---

# Tree the current local directory.
root_dir = '.'

# --- Main ---

# Define our subprocess.run() command.

# Tree the current local directory
# command = 'cmd /c tree'

# Optional
command = 'cmd /c tree' + ' ' + root_dir + options

# Visual aid
# print('')

# Run our subprocess.run() command and capture its output.
# raw_output is subprocess.CompletedProcess object.
raw_output = subprocess.run(command, capture_output=True)

# "temp_output" is a bytes() object of the text produced by "tree".
temp_output = raw_output.stdout

# Clean up whatever text was produced by "tree" at the command line.
# Turn "temp_output" into a decoded string (from a bytes() object).
# Code Page 437 should represent any extended symbols correctly.
text_output = temp_output.decode('cp437')

# Used for extended output
if ascii_tree is False:

    # Build our (pipe) symbols variable required for directory matching.
    dir_prefix = bytes('\xc4\xc4\xc4', 'cp1252')
    decoded_prefix = dir_prefix.decode('cp437')

# Used for ASCII output
if ascii_tree is True:

    # Build our (hyphen, etc.) symbols variables for directory matching.
    dir_prefix_ascii_A = '+---'
    dir_prefix_ascii_B = '\\---'

# Build a list holding our "tree" command output.
# We can use string.split('\r\n') because we use e.g. "cp437" for decoding.
tree_list = text_output.split('\r\n')

# Process our tree_list[]. Add a "\" to any line that is a directory.
for line in tree_list:

    # Copy our current tree_list[] line
    entry = line

    # Replace any eight digit random numbers and ":" in our "Volume"
    # information. These are apparently side-effects of this script.
    if line.startswith('Volume'):

        # Our eight digit random number in front of the "Volume" ID apparently
        # has a constant position (in line 2). Therefore, we make a list of the
        # words in that line and remove the correct element in that word list,
        # then reconstruct the line.

        # Make our word list
        words = entry.split()

        # Remove our random eight digit number. "del words[4]" would work as
        # well (with no element returned).
        random_number = words.pop(4)

        # Accounts for lists starting at 0 and lengths starting at 1.
        words_max = len(words) - 1

        # Get the string value of the word in our last words[] element.
        last_word = words[words_max]

        # Blanking is done *after* we have copied our entry line to words[].
        entry = ''

        # Reconstruct our current line (sans our "random_number").
        for word in words:
            if word is not last_word:
                entry += word + ' '
            else:
                entry += word

        # Replace ":" with "-", as output by the "tree" command.
        entry = entry.replace(':', '-')

    # Add a trailing slash to our root directory, including "." (e.g. "C:.\")
    if ':\\' in line or ':.' in line:
        entry += '\\'

    # Used for extended output
    if ascii_tree is False:

        # Check if our "decoded_prefix" i.e. extended pipe characters
        # are in the given line (indicating a directory).
        if decoded_prefix in line:

            # If so, add a trailing slash "\"
            entry += '\\'

    # Used for ASCII output
    if ascii_tree is True:

        # Check if "dir_prefix_ascii_A" or "dir_prefix_ascii_B" i.e. ASCII
        # "+---" or "\---" are in the given line (indicating a directory).
        if dir_prefix_ascii_A in line or dir_prefix_ascii_B in line:

            # If so, add a trailing slash "\"
            entry += '\\'

    # Display our final (modified) tree line.
    # Corrects for a final blank line in our tree_list[].
    if entry != '':
        print(entry)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .