g | x | w | all
Bytes Lang Time Link
106Tcl170114T233138Zsergiol
221C# .NET Core170114T175659Zsergiol
132Python 2160718T164722Zmbomb007
205Java 8180327T194755ZJakob
089Perl170115T002249Zuser6440
237Batch160718T122726ZNeil
147PowerShell160718T161956ZThePoShW
180PHP160718T134952ZTitus
176SML160717T233732ZLaikoni
048Dyalog APL160717T223132ZAdá
054bash160716T212233ZDoorknob

Tcl, 106 bytes

proc L {f n\ 0} {puts [string repe \t $n][file ta $f]
lmap c [glob -n -d $f *] {L $c [expr $n+1]}}
L $argv

Try it online!

C# (.NET Core), 221 bytes

namespace System.IO{class P{static int n;static void Main(String[]a){Console.WriteLine(new string(' ',n++)+Path.GetFileName(a[0]));try{foreach(var f in Directory.GetFileSystemEntries(a[0])){a[0]=f;Main(a);}}catch{}n--;}}}

Try it online!


The ungolf:

using System.IO;
using System;

class P
{
    static int n=0;
    static void Main(String[] a)
    {
        for (int i=0;i<n;i++) Console.Write('   ');
        Console.WriteLine(Path.GetFileName(a[0]));
        n++;

        if(Directory.Exists(a[0]))
            foreach (String f in Directory.GetFileSystemEntries(a[0]))
                Main(new String[]{f});
        n--;
    }
}

First time I ever recursed a Main function!

I believe a person that has fresher knowledge of C# can golf it more, as I didn't program on C# for some time!

Python 2, 132 bytes

Modified from this SO answer. Those are tabs for indentation, not spaces. Input will be taken like "C:/" or /var.

import os
p=input()
for r,d,f in os.walk(p):
    t=r.replace(p,'').count('/');print' '*t+os.path.basename(r)
    for i in f:print'   '*-~t+i

Try it online - It's pretty interesting that I'm allowed to browse the directory online...

from os import*
p=input()
for r,d,f in walk(p):
    t=r.replace(p,'').count(sep);print' '*t+path.basename(r)
    for i in f:print'   '*-~t+i

Java 8, 205 bytes

import java.io.*;public interface M{static void p(File f,String p){System.out.println(p+f.getName());if(!f.isFile())for(File c:f.listFiles())p(c,p+"\t");}static void main(String[]a){p(new File(a[0]),"");}}

This is a full program submission which takes input from its first command-line argument (not explicitly permitted, but done by many others) and prints output to standard out.

Try It Online (note different interface name)

Ungolfed

import java.io.*;

public interface M {
    static void p(File f, String p) {
        System.out.println(p + f.getName());
        if (!f.isFile())
            for (File c : f.listFiles())
                p(c, p + "\t");
    }

    static void main(String[] a) {
        p(new File(a[0]), "");
    }
}

Perl, 89 bytes

It's useful when there's a find module in the core distribution. Perl's File::Find module does not traverse the tree in alphabetic order, but the spec didn't ask for that.

/usr/bin/perl -MFile::Find -nE 'chop;find{postprocess,sub{--$d},wanted,sub{say" "x$d.$_,-d$_&&++$d&&"/"}},$_'

The script proper is 76 bytes, I counted 13 bytes for the command-line options.

Batch, 237 bytes

@echo off
echo %~1\
for /f %%d in ('dir/s/b %1')do call:f %1 %%~ad "%%d"
exit/b
:f
set f=%~3
call set f=%%f:~1=%%
set i=
:l
set i=\t%i%
set f=%f:*\=%
if not %f%==%f:*\=% goto l
set a=%2
if %a:~0,1%==d set f=%f%\
echo %i%%f%

Where \t represents the literal tab character. This version includes trailing \s on directories but 41 bytes can be saved if they are not needed.

PowerShell, 147 bytes

param($a)function z{param($n,$d)ls $n.fullname|%{$f=$_.mode[0]-ne"d";Write-Host(" "*$d*4)"$($_.name)$(("\")[$f])";If(!$f){z $_($d+1)}}}$a;z(gi $a)1

Man, I feel like PS should be able to do something like the bash answer, but I'm not coming up with anything shorter than what I've got here.

Explanation:

param($a)                     # assign first passed parameter to $a
function z{param($n,$d) ... } # declare function z with $n and $d as parameters
ls $n.fullname                # list out contents of directory
|%{ ... }                     # foreach
$f=$_.namde[0]-ne"d"          # if current item is a file, $f=true
Write-Host                    # writes output to the console
(" "*$d*4)                    # multiplies a space by the depth ($d) and 4
"$($_.name)$(("\")[$f])"      # item name + the trailing slash if it is a directory
;if(!$f){z $_($d+1)}          # if it is a directory, recursively call z
$a                            # write first directory to console
z(gi $a)1                     # call z with $a as a directoryinfo object and 1 as the starting depth

PHP, 180 bytes

function d($p,$e){$s=opendir($p);echo$b=str_repeat("\t",$e++),$e?basename($p)."/":$p,"
";while($f=readdir($s))echo preg_match("#^\.#",$f)?"":is_dir($p.$f)?d("$p$f/",$e):"$b\t$f
";}

with glob, 182 bytes (probably 163 in future php)

function g($p,$e){echo$b=str_repeat("\t",$e),$e++?basename($p)."/":$p,"
";foreach(glob(preg_replace("#[*?[]#","[$1]",$p)."*",2)as$f)echo is_dir($f)?g($f,$e):"$b\t".basename($f)."
";}

with iterators, 183 bytes
(well, not purely iterators: I used implicit SplFileInfo::__toString() to golf $f->getBaseName() and $f->isDir() to the old PHP 4 functions.)

function i($p){echo"$p
";foreach($i=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($p),1)as$f)echo str_repeat("\t",1+$i->getDepth()),basename($f),is_dir($f)?"/":"","
";}

SML, 176 bytes

open OS.FileSys;val! =chDir;fun&n w=(print("\n"^w^n);!n;print"/";c(openDir(getDir()))(w^"\t");!"..")and c$w=case readDir$of SOME i=>(&i w handle _=>();c$w)|x=>()fun%p=(&p"";!p)

Declares (amongst others) a function % which takes a string as argument. Call with % "C:/Some/Path"; or % (getDir()); for the current directory.

I'm using the normally rather functionally used language StandardML whose FileSys-Library I discovered after reading this challenge.

The special characters !, &, $ and % have no special meaning in the language itself and are simply used as identifiers; however they can't be mixed with the standard alphanumeric identifiers which allows to get rid of quite some otherwise needed spaces.

open OS.FileSys;
val ! = chDir;                       define ! as short cut for chDir

fun & n w = (                        & is the function name
                                     n is the current file or directory name
                                     w is a string containing the tabs
    print ("\n"^w^n);                ^ concatenates strings
    ! n;                             change in the directory, this throws an 
                                     exception if n is a file name
    print "/";                       if we are here, n is a directory so print a /
    c (openDir(getDir())) (w^"\t");  call c with new directory and add a tab to w
                                     to print the contents of the directory n
    ! ".."                           we're finished with n so go up again
)
and c $ w =                          'and' instead of 'fun' must be used 
                                     because '&' and 'c' are mutual recursive
                                     $ is a stream of the directory content
    case readDir $ of                case distinction whether any files are left
        SOME i => (                  yes, i is the file or directory name
            & i w handle _ => ();    call & to print i an check whether it's a 
                                     directory or not, handle the thrown exception 
            c $ w )                  recursively call c to check for more files in $
        | x    => ()                 no more files, we are finished

fun % p = (                          % is the function name, 
                                     p is a string containing the path
    & p "";                          call & to print the directory specified by p
                                     and recursively it's sub-directories
    ! p                              change back to path p due to the ! ".." in &
)

Can be compiled like this with SML/NJ or with Moscow ML* by prefixing with load"OS";.

*See mosml.org, can't post more than 2 links.

Dyalog APL, 48 bytes

(⊂∘⊃,1↓'[^\\]+\\'⎕R'    ')r[⍋↑r←⎕SH'dir/s/b ',⍞]

prompt for character input

'dir/s/b ', prepend text

⎕SH execute in shell

r← store in r

make list of strings into character matrix

indices for ascending sorting

r[...] reorder r [sorted]

(...) on the standard out of the shell command, do:

'[^\\]+\\'⎕R' ' regex replace backslash-terminated runs of non-backslashes by four spaces

1↓ drop the first line

⊂∘⊃, prepend the enclosed first [line]

Result of inputting "\tmp" to the prompt begins as follows on my computer:

C:\tmp\12u64
            keyboards64.msi
            netfx64.exe
            setup.exe
            setup_64_unicode.msi
            setup_dotnet_64.msi
        AdamsReg.reg
        AdamsReg.zip
        qa.dws
        ride-experimental
            win32
                d3dcompiler_47.dll
                icudtl.dat
                libEGL.dll

bash, 61 58 54 bytes

find "$1" -exec ls -Fd {} \;|perl -pe's|.*?/(?!$)|  |g'

Takes input as a command line argument, outputs on STDOUT.

Note that the spaces near the end before the |g are actually a tab character (SE converts them to spaces when displaying posts).

find              crawl directory tree recursively
"$1"              starting at the input directory
-exec             and for each file found, execute...
ls -Fd {} \;      append a trailing slash if it's a directory (using -F of ls)
|perl -pe         pipe each line to perl
'
s|                replace...
.*?/              each parent directory in the file's path...
(?!$)             that doesn't occur at the end of the string...
|    |            with a tab character...
g                 globally
'

Thanks to @Dennis for 4 bytes!