Escreva um programa para exibir a casa na árvore de diretórios

9

Dado um diretório (como C:/), fornecido pelo stdin ou lido de um arquivo, produza uma árvore de diretórios, com cada arquivo / pasta recuado com base em sua profundidade.

Exemplo

Se eu tiver um C:/carro que só contém duas pastas fooe bar, e baré ao mesmo tempo vazia foocontém baz.txt, em seguida, executando com a entrada C:/produz:

C:/
    bar/
    foo/
        baz.txt

durante a execução com entrada C:/foo/deve produzir

foo/
    baz.txt

Como este é um codegolf, a menor contagem de bytes vence. As extensões de arquivo (como baz.txt) são opcionais. Notas extras: os arquivos ocultos podem ser ignorados, os diretórios devem realmente existir, pode-se supor que os arquivos não contenham caracteres não imprimíveis ou novas linhas, mas todos os outros caracteres ASCII imprimíveis são adequados (nomes de arquivos com espaços devem ser suportados). A saída pode ser gravada em arquivo ou stdout. As indentações podem ser compostas por um caractere de tabulação ou quatro espaços.

Mathime
fonte
11
Nota extra: esta questão está mal formatada, portanto uma reformatação seria apreciada.
Mathime 16/07/2016
Os idiomas que não têm acesso aos arquivos são desqualificados automaticamente?
Leaky Nun
Quais nomes de arquivos precisam ser suportados? Arquivos com espaços em seus nomes? Com novas linhas? Com caracteres não imprimíveis? E os arquivos ocultos (começando com .)?
Maçaneta
11
@LeakyNun A saída da pergunta de referência é uma matriz de matrizes. Esta pergunta requer que uma representação da árvore de diretórios seja impressa no stdout.
Mathime 16/07/2016
11
A entrada pode ser um parâmetro de string para uma função?
Mbomb007

Respostas:

10

bash, 61 58 54 bytes

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

Recebe a entrada como argumento da linha de comando e sai em STDOUT.

Observe que os espaços próximos ao final antes da |gsão realmente um caractere de tabulação (o SE os converte em espaços ao exibir postagens).

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
'

Obrigado a @Dennis por 4 bytes!

Maçaneta da porta
fonte
2

Dyalog APL , 48 bytes

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

prompt para entrada de caracteres

'dir/s/b ', anexar texto

⎕SH executar em shell

r←armazenar em r

faça a lista de strings na matriz de caracteres

índices para classificação crescente

r[... ]reordenar r [classificado]

(... )no comando padrão fora do shell, faça:

'[^\\]+\\'⎕R' ' regex substitui execuções terminadas por barra invertida por quatro espaços

1↓ largar a primeira linha

⊂∘⊃, preceda a primeira [linha] fechada

O resultado da inserção de "\ tmp" no prompt começa da seguinte maneira no meu computador:

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

Adão
fonte
Os diretórios não deveriam ter caracteres \ à direita?
Neil
2

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)

Declara (entre outras) uma função %que aceita uma string como argumento. Ligue com % "C:/Some/Path";ou % (getDir());para o diretório atual.

Estou usando a linguagem StandardML, normalmente bastante funcional, cuja FileSysbiblioteca-descobri depois de ler este desafio.

Os caracteres especiais !, &, $e %não têm nenhum significado especial em sua própria língua e são simplesmente usadas como identificadores; no entanto, eles não podem ser misturados com os identificadores alfanuméricos padrão, o que permite eliminar alguns espaços necessários.

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 &
)

Pode ser compilado assim com SML / NJ ou com Moscow ML * prefixando com load"OS";.

* Veja mosml.org, não é possível postar mais de 2 links.

Laikoni
fonte
1

C # (.NET Core) , 222 bytes

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

Experimente online!


O 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("\t");
        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--;
    }
}

Primeira vez em que recursionei uma Mainfunção!

Acredito que uma pessoa que tenha um conhecimento mais recente de C # possa jogar mais, porque eu não programava em C # há algum tempo!

sergiol
fonte
0

PHP, 180 bytes

  • primeiro argumento: o caminho deve ter uma barra final (ou barra invertida)
  • segundo argumento: o nível padrão é NULLe será interpretado como 0por str_repeat; emitirá um aviso se não for fornecido

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
";}
  • exibe arquivos e diretórios ocultos, mas não recursa diretórios ocultos,
    adicione parênteses is_dir(...)?d(...):"..."para remover entradas ocultas da saída (+2)
    substitua "#^\.#"por #^\.+$#para exibir / recursar entradas ocultas, mas pule entradas de ponto (+2)
  • pode gerar erros quando os diretórios estão aninhados muito profundamente. Inserir closedir($s);antes da final }para corrigir (+13)
  • falhará se um diretório contiver uma entrada sem nome, preceda false!==a condição while para corrigir (+8)

com glob, 182 bytes (provavelmente 163 no php futuro)

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)."
";}
  • não exibe ou recursa arquivos / diretórios ocultos
  • 2 apoia GLOB_MARK , acrescentará uma barra a todos os nomes de diretório, assim comols -F
  • os preg_replacecaracteres especiais escapes glob que
    eu poderia ter abusado preg_quotepor isso (-19); mas isso falharia nos sistemas Windows, pois a barra invertida é o separador de diretórios lá.
  • O php pode incluir em breve uma função glob_quote , que permitirá o mesmo golfe preg_quotee o trabalho em todos os sistemas.

com iteradores, 183 bytes
(bem, não puramente iteradores: usei implícito SplFileInfo::__toString()no golfe $f->getBaseName()e $f->isDir()nas funções antigas do PHP 4.)

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)?"/":"","
";}
  • nenhuma barra final necessária
  • exibe e recursa entradas ocultas ( ls -a)
  • inserir ,4096ou ,FilesystemIterator::SKIP_DOTSantes ),1para pular entradas de ponto (+5) ( ls -A)
  • flag 1significaRecursiveIteratorIterator::SELF_FIRST
Titus
fonte
0

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

Cara, eu sinto que o PS deve ser capaz de fazer algo como a resposta do bash, mas não estou apresentando nada mais curto do que o que tenho aqui.

Explicação:

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
ThePoShWolf
fonte
0

Python 2, 138 bytes

Modificado a partir desta resposta SO . Essas são guias para recuo, não espaços. Entrada será tomada como "C:/".

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

Experimente online - é bem interessante que eu tenha permissão para navegar no diretório no Ideone ...

Mesmo comprimento:

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
mbomb007
fonte
0

Lote, 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%

Onde \ t representa o caractere de tabulação literal. Esta versão inclui os \s finais nos diretórios, mas 41 bytes podem ser salvos se não forem necessários.

Neil
fonte
os `\` s finais não são necessários
somente ASCII
0

Perl, 89 bytes

É útil quando há um módulo de localização na distribuição principal. O módulo File :: Find do Perl não atravessa a árvore em ordem alfabética, mas a especificação não pediu isso.

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

O script propriamente dito é 76 bytes, contei 13 bytes para as opções de linha de comando.

daniel
fonte
0

Tcl , 116 bytes

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

Experimente online!

sergiol
fonte
0

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]),"");}}

Este é um envio completo do programa que recebe a entrada do seu primeiro argumento de linha de comando (não é explicitamente permitido, mas é feito por muitos outros) e imprime a saída na saída padrão.

Experimente Online (observe o nome da interface diferente)

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]), "");
    }
}
Jakob
fonte