Print directory tree but exclude a folder on windows cmd
Asked Answered
F

5

17

I want to print a directory tree excluding a folder. I already know the basic way to print the tree like this:

tree /A > tree.txt

I want to achieve something like this:

tree /A [exclude folder node_modules] > tree.txt
Fanlight answered 5/5, 2017 at 16:48 Comment(1)
The tree command does not support that functionality. Type tree /? from a command prompt to see what it does support.Didier
A
23

The standard tree.com utility does not support excluding directories.

  • If you only need to exclude directories by name themselves and not also their entire subtree (child directories and their descendants), see nferrell's answer.

  • If you need to exclude the entire subtree of directories matching a given name, more work is needed - see below.

Below is the source code for PowerShell function tree, which emulates the behavior of tree.com command, while also:

  • offering selective exclusion of subtrees by name
    Note: You may specify multiple names separated by , and the names can be wildcard patterns - note that they only apply to the directory name, however, not the full path.

  • offering cross-platform support
    Note: Be sure to save your script with UTF-8 encoding with BOM for the script to function properly without -Ascii.

  • offering switch -IncludeFiles to also print files.

With the function below loaded, the desired command looks like this:

tree -Exclude node_modules -Ascii > tree.txt

Run tree -? or Get-Help tree for more information.


tree source code (add to your $PROFILE, for instance; PSv4+):

function tree {
    <#
    .SYNOPSIS
    Prints a directory's subtree structure, optionally with exclusions.

    .DESCRIPTION
    Prints a given directory's subdirectory structure recursively in tree form,
    so as to visualize the directory hierarchy similar to cmd.exe's built-in
    'tree' command, but with the added ability to exclude subtrees by directory
    names.

    NOTE: Symlinks to directories are not followed; a warning to that effect is
            issued.

    .PARAMETER Path
    The target directory path; defaults to the current directory.
    You may specify a wildcard pattern, but it must resolve to a single directory.

    .PARAMETER Exclude
    One or more directory names that should be excluded from the output; wildcards
    are permitted. Any directory that matches anywhere in the target hierarchy
    is excluded, along with its subtree.
    If -IncludeFiles is also specified, the exclusions are applied to the files'
    names as well.

    .PARAMETER IncludeFiles
    By default, only directories are printed; use this switch to print files
    as well.

    .PARAMETER Ascii
    Uses ASCII characters to visualize the tree structure; by default, graphical
    characters from the OEM character set are used.

    .PARAMETER IndentCount
    Specifies how many characters to use to represent each level of the hierarchy.
    Defaults to 4.

    .PARAMETER Force
    Includes hidden items in the output; by default, they're ignored.

    .NOTES
    Directory symlinks are NOT followed, and a warning to that effect is issued.

    .EXAMPLE
    tree

    Prints the current directory's subdirectory hierarchy.

    .EXAMPLE
    tree ~/Projects -Ascii -Force -Exclude node_modules, .git

    Prints the specified directory's subdirectory hierarchy using ASCII characters
    for visualization, including hidden subdirectories, but excluding the
    subtrees of any directories named 'node_modules' or '.git'.
    #>

    [CmdletBinding(PositionalBinding = $false)]
    param(
        [Parameter(Position = 0)]
        [string] $Path = '.',
        [string[]] $Exclude,
        [ValidateRange(1, [int]::MaxValue)]
        [int] $IndentCount = 4,
        [switch] $Ascii,
        [switch] $Force,
        [switch] $IncludeFiles
    )

    # Embedded recursive helper function for drawing the tree.
    function _tree_helper {

        param(
            [string]$literalPath,
            [string]$prefix
        )

        # Get all subdirs. and, if requested, also files.
        $items = Get-ChildItem -Directory:(-not $IncludeFiles) -LiteralPath $LiteralPath -Force:$Force

        # Apply exclusion filter(s), if specified.
        if ($Exclude -and $items) {
            $items = $items.Where({ $name = $_.Name; -not $Exclude.Where({ $name -like $_ },'First') })
        }

        if (-not $items) { return } # no subdirs. / files, we're done

        $i = 0
        foreach ($item in $items) {
            $isLastSibling =++ $i -eq $items.Count
            # Print this dir.
            $prefix + $(if ($isLastSibling) { $chars.last } else { $chars.interior }) + $chars.hline * ($indentCount - 1) + $item.Name
            # Recurse, if it's a subdir (rather than a file).
            if ($item.PSIsContainer) {
                if ($item.LinkType) { Write-Warning "Not following dir. symlink: $item"; continue }
                $subPrefix = $prefix + $(if ($isLastSibling) { $chars.space * $indentCount } else { $chars.vline + $chars.space * ($indentCount - 1) })
                _tree_helper $item.FullName $subPrefix
            }
        }
    } # function _tree_helper

    # Hashtable of characters used to draw the structure
    $ndx = [bool] $Ascii
    $chars = @{
        interior = ('├','+')[$ndx]
        last = ('└','\\')[$ndx]
        hline = ('─','-')[$ndx]
        vline = ('|','|')[$ndx]
        space = " "
    }

    # Resolve the path to a full path and verify its existence and expected type.
    $literalPath = (Resolve-Path $Path).Path
    if (-not $literalPath -or -not (Test-Path -PathType Container -LiteralPath $literalPath) -or $literalPath.Count -gt 1) { throw "$Path must resolve to a single, existing directory." }

    # Print the target path.
    $literalPath

    # Invoke the helper function to draw the tree.
    _tree_helper $literalPath

}

Note:

  • The third-party Get-PSTree cmdlet (installable via Install-Module PSTree -Scope CurrentUser, for instance) offers a more fully featured implementation that notably includes reporting (cumulative) directory sizes (though no support for excluding directories as of this writing).
Akers answered 5/5, 2017 at 17:10 Comment(5)
@Akers This code only prints the folders. How to print the all the files in the folders including hidden files.Almeria
@PankajMahato: Yes, the code originally printed just folders, given that's what the standard tree.com utility does too. However, I've just added the -IncludeFiles switch, which now allows you to print file names as well. As before, -Force includes hidden items.Akers
This just gives me Too many parameters - <FolderNameToBeExcluded>; Any ideas? Tried on both CMD and PowerShell.Helfand
@anand_v.singh: The error message implies that you ran C:\WINDOWS\system32\tree.com, from CMD. What this answer does is to define a PowerShell function named tree - which you have to define in your session first - which emulates tree.com's behavior while also adding new features and therefore supporting additional parameters.Akers
Thanks for the edit, @CodeByAidan, but note that ```pwsh doesn't work for syntax highlighting: it falls back to guessing the language, which doesn't always work; for now, ```sh is the best stopgap for imperfect, but consistent highlighting - see meta.stackoverflow.com/q/421016/45375. Also, I prefer to place a space between a type constraint and a (parameter) variable; e.g. [string] $Path rather than [string]$Path.Akers
H
4

Using PSTree Module (Disclaimer: I'm the maintainer of this Module) you can exclude files and folders using its -Exclude Parameter.

A before and after comparison below:

PS ..\PSTree> pstree .\src\PSTree\ -RecursiveSize

   Source: C:\Users\User\Documents\PSTree\src\PSTree

Mode            Length Hierarchy
----            ------ ---------
d----        326.81 KB PSTree
-a---        931.00  B ├── ExceptionHelpers.cs
-a---          4.09 KB ├── PathExtensions.cs
-a---        442.00  B ├── PSTree.csproj
-a---        900.00  B ├── PSTreeCache.cs
-a---          1.06 KB ├── PSTreeDirectory.cs
-a---          1.66 KB ├── PSTreeExtensions.cs
-a---        517.00  B ├── PSTreeFile.cs
-a---        399.00  B ├── PSTreeFileSystemInfo.cs
-a---          1.61 KB ├── PSTreeFileSystemInfo_T.cs
-a---        626.00  B ├── PSTreeIndexer.cs
d----        186.37 KB ├── obj
-a---         12.05 KB │   ├── project.assets.json
-a---        642.00  B │   ├── project.nuget.cache
-a---          2.12 KB │   ├── PSTree.csproj.nuget.dgspec.json
-a---          1.10 KB │   ├── PSTree.csproj.nuget.g.props
-a---        534.00  B │   ├── PSTree.csproj.nuget.g.targets
d----         82.03 KB │   ├── release
d----         82.03 KB │   │   └── netstandard2.0
d----         87.92 KB │   └── Debug
d----         87.92 KB │       └── netstandard2.0
d----          1.15 KB ├── Internal
-a---          1.15 KB │   └── _FormattingInternals.cs
d----          6.43 KB ├── Commands
-a---          6.43 KB │   └── GetPSTreeCommand.cs
d----        120.72 KB └── bin
d----         54.43 KB     ├── release
d----         54.43 KB     │   └── netstandard2.0
d----         66.28 KB     └── Debug
d----         66.28 KB         └── netstandard2.0
PS ..\PSTree> pstree .\src\PSTree\ -RecursiveSize -Exclude *obj, *bin

   Source: C:\Users\User\Documents\PSTree\src\PSTree

Mode            Length Hierarchy
----            ------ ---------
d----         19.72 KB PSTree
-a---        931.00  B ├── ExceptionHelpers.cs
-a---          4.09 KB ├── PathExtensions.cs
-a---        442.00  B ├── PSTree.csproj
-a---        900.00  B ├── PSTreeCache.cs
-a---          1.06 KB ├── PSTreeDirectory.cs
-a---          1.66 KB ├── PSTreeExtensions.cs
-a---        517.00  B ├── PSTreeFile.cs
-a---        399.00  B ├── PSTreeFileSystemInfo.cs
-a---          1.61 KB ├── PSTreeFileSystemInfo_T.cs
-a---        626.00  B ├── PSTreeIndexer.cs
d----          1.15 KB ├── Internal
-a---          1.15 KB │   └── _FormattingInternals.cs
d----          6.43 KB └── Commands
-a---          6.43 KB     └── GetPSTreeCommand.cs

The cmdlet also offers a -Include Parameter for inclusive filtering as well as other features.

If you want to try it out it can be easily installed through the PowerShell Gallery:

Install-Module PSTree -Scope CurrentUser
Hansel answered 31/10, 2023 at 2:27 Comment(0)
W
2

In Powershell, just use Where-Object and exclude the folder names you want (put a * wildcard on the front since it can be difficult to know how many spaces and special characters are on the same line as the folder name):

tree /A | Where-Object {$_ -notlike "*node_modules"} > tree.txt

Edit: This won't exclude subfolders though, it will only exclude the folders you name in the Where-Object clause.

Weighted answered 6/5, 2017 at 0:23 Comment(1)
it didn't exclude its subdirectories.Bergquist
V
1

This isn't exactly a complete answer, but should allow you to accomplish what you want with a little work. If you used the Show-Tree code from the PowerShell Community Extensions as a base, and then added in something to filter out folders, you could accomplish what you desire. This is something that should be totally doable, really, since this little bit of code shows how to define a string to exclude (wildcards accepted in a -like format), then get a recursive folder structure and denote if that is an excluded folder, or is contained within an excluded folder.

$DirExcludes = @()
$ToExclude = 'temp*'
GCI -Recurse -Directory |%{
    Switch($_){
        {$_.Name -ilike $ToExclude} {
            $DirExcludes += $_.FullName;
            Write-Host $_.FullName -ForegroundColor Red
            Continue}
        {$DirExcludes -and $_.FullName -match "^($(($DirExcludes|%{[regex]::Escape($_)}) -join '|'))"} {
            Write-Host $_.FullName -ForegroundColor DarkRed
            Continue
            }
        default {Write-Host $_.FullName -ForegroundColor Blue}
    }
}

When I ran this against my user profile it showed that it caught both a 'Temp' folder and a 'Template' folder, and marked those and each subfolder of those to be excluded. You should be able to get the code of the Show-Tree command by doing:

Get-Command Show-Tree -ShowCommandInfo | % Definition

Then you would just need to devise how to incorporate something similar to what I have above into that code, and you can make a new function to accomplish what you want.

Vocation answered 5/5, 2017 at 17:57 Comment(0)
W
1

Save this code below and run:

import os

def generate_folder_structure(path, exclusions, output_file):
    with open(output_file, 'w') as f:
        for root, dirs, files in os.walk(path):
            for exclusion in exclusions:
                if exclusion in dirs:
                    dirs.remove(exclusion)
            level = root.replace(path, '').count(os.sep)
            indent = ' ' * 4 * (level)
            f.write('{}{}/\n'.format(indent, os.path.basename(root)))
            subindent = ' ' * 4 * (level + 1)
            for file in files:
                f.write('{}{}\n'.format(subindent, file))

if __name__ == "__main__":
    base_path = r'C:\Users\awy\repos\databricks-dp-lib'
    exclusions = ['venv']
    output_file = 'folder_structure1.txt'
    generate_folder_structure(base_path, exclusions, output_file)
Woolf answered 31/10, 2023 at 1:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.