เขียนโปรแกรมเพื่อแสดงทรีไดเรกทอรี


9

ได้รับไดเรกทอรี (เช่นC:/) ที่ได้รับจาก stdin หรืออ่านจากไฟล์สร้างทรีไดเรกทอรีโดยแต่ละไฟล์ / โฟลเดอร์เยื้องตามความลึกของมัน

ตัวอย่าง

หากฉันมีC:/ไดรฟ์ที่มีเพียงสองโฟลเดอร์fooและbarและbarว่างเปล่าในขณะที่fooมีbaz.txtแล้วทำงานด้วยการป้อนข้อมูลC:/ผลิต:

C:/
    bar/
    foo/
        baz.txt

ในขณะที่ทำงานกับอินพุตC:/foo/ควรผลิต

foo/
    baz.txt

เช่นนี้เป็น codegolf นับไบต์ต่ำสุดชนะ นามสกุลไฟล์ (เช่นbaz.txt) เป็นทางเลือก หมายเหตุเพิ่มเติม: ไฟล์ที่ซ่อนอยู่สามารถถูกละเว้นไดเรกทอรีต้องมีอยู่จริงมันสามารถสันนิษฐานได้ว่าไฟล์ไม่มีอักขระที่ไม่สามารถพิมพ์ได้หรือบรรทัดใหม่ แต่อักขระ ASCII ที่พิมพ์ได้อื่นทั้งหมดนั้นใช้ได้ (ต้องรองรับชื่อไฟล์ที่มีช่องว่าง) สามารถเขียนเอาต์พุตไปยังไฟล์หรือ stdout ได้ การเยื้องอาจประกอบด้วยอักขระแท็บหรือช่องว่าง 4 ช่อง


1
หมายเหตุเพิ่มเติม: คำถามนี้มีรูปแบบไม่ดีดังนั้นการจัดรูปแบบใหม่จะได้รับการชื่นชม
Mathime

ภาษาที่ไม่มีสิทธิ์เข้าถึงไฟล์ถูกตัดสิทธิ์โดยอัตโนมัติหรือไม่?
Leun Nun

ต้องรองรับชื่อไฟล์อะไร ไฟล์ที่มีช่องว่างในชื่อของพวกเขา? มีการขึ้นบรรทัดใหม่หรือไม่ ด้วยอักขระที่ไม่สามารถพิมพ์ได้? สิ่งที่เกี่ยวกับไฟล์ที่ซ่อน (เริ่มต้นด้วย.)
Doorknob

1
@LeakyNun ผลลัพธ์ของคำถามอ้างอิงคืออาร์เรย์ของอาร์เรย์ คำถามนี้ต้องการการแสดงแผนผังไดเรกทอรีที่จะพิมพ์ไปยัง stdout
Mathime

1
อินพุตสามารถเป็นพารามิเตอร์สตริงของฟังก์ชันได้หรือไม่?
mbomb007

คำตอบ:


10

bash, 61 58 54 ไบต์

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

รับอินพุตเป็นอาร์กิวเมนต์บรรทัดคำสั่งเอาต์พุตบน STDOUT

โปรดทราบว่าช่องว่างใกล้ถึงจุดสิ้นสุดก่อนที่|gจะเป็นอักขระแท็บ (SE จะแปลงเป็นช่องว่างเมื่อแสดงโพสต์)

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
'

ขอบคุณ@Dennisสำหรับ 4 ไบต์!


2

Dyalog APL ขนาด 48 ไบต์

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

พรอมต์สำหรับการป้อนอักขระ

'dir/s/b ', เติมข้อความ

⎕SH ดำเนินการในเปลือก

r←ร้านค้าในr

ทำรายการของสตริงลงในเมทริกซ์อักขระ

ดัชนีสำหรับการเรียงลำดับจากน้อยไปมาก

r[... ]สั่งซื้อR [เรียง]

(... )บนมาตรฐานจากคำสั่งเชลล์ให้ทำ:

'[^\\]+\\'⎕R' ' regex แทนที่แบ็กสแลชสิ้นสุดการรันของ nonslash โดยช่องว่างสี่ช่อง

1↓ วางบรรทัดแรก

⊂∘⊃, เติมคำนำหน้าบรรทัดแรก

ผลลัพธ์ของการป้อน "\ tmp" ไปยังพรอมต์เริ่มต้นดังนี้บนคอมพิวเตอร์ของฉัน:

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


ไดเรกทอรีควรจะมีส่วนท้าย \ อักขระไม่ใช่หรือ
Neil


2

SML , 176 ไบต์

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)

ประกาศฟังก์ชั่น%ซึ่งรับค่าสตริงเป็นอาร์กิวเมนต์ โทรด้วย% "C:/Some/Path";หรือ% (getDir());สำหรับไดเรกทอรีปัจจุบัน

ฉันใช้ภาษา StandardML ที่ใช้งานได้ค่อนข้างปกติซึ่งมี - FileSysห้องสมุดที่ฉันค้นพบหลังจากอ่านความท้าทายนี้

ตัวอักษรพิเศษ!, &, $และ%ไม่มีความหมายพิเศษในภาษาของตัวเองและมีการใช้เพียงเป็นตัวระบุ; อย่างไรก็ตามพวกเขาไม่สามารถผสมกับตัวระบุตัวเลขและตัวอักษรมาตรฐานที่อนุญาตให้กำจัดช่องว่างที่จำเป็น

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

สามารถรวบรวมเช่นนี้กับSML / นิวเจอร์ซีย์หรือกับมอสโก ML * โดย prefixing load"OS";ด้วย

* ดูmosml.orgไม่สามารถโพสต์มากกว่า 2 ลิงก์


1

C # (. NET Core) , 222 ไบต์

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--;}}}

ลองออนไลน์!


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--;
    }
}

ครั้งแรกที่ฉันเคยเรียกใช้Mainฟังก์ชั่นซ้ำ!

ฉันเชื่อว่าคนที่มีความรู้ที่สดใหม่ของ C # สามารถเล่นกอล์ฟได้มากกว่านี้เพราะฉันไม่ได้เขียนโปรแกรมบน C # สักพัก!


0

PHP, 180 ไบต์

  • อาร์กิวเมนต์แรก: เส้นทางต้องมีเครื่องหมายสแลช (หรือเครื่องหมายแบ็กสแลช)
  • อาร์กิวเมนต์ที่สอง: ระดับเริ่มต้นที่NULLและจะถูกตีความว่าเป็น0โดยstr_repeat; จะส่งคำเตือนหากไม่ได้ระบุไว้

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
";}
  • แสดงไฟล์และไดเรกทอรีที่ซ่อนอยู่ แต่ไม่เรียกคืนไดเรกทอรีที่ซ่อนอยู่
    เพิ่มวงเล็บไปรอบ ๆis_dir(...)?d(...):"..."เพื่อลบรายการที่ซ่อนอยู่จากเอาท์พุท (+2)
    แทนที่"#^\.#"ด้วย#^\.+$#เพื่อแสดง / เรียกคืนรายการที่ซ่อนอยู่ แต่ข้ามรายการ dot (+2)
  • อาจทำให้เกิดข้อผิดพลาดเมื่อไดเรกทอรีซ้อนกันลึกเกินไป แทรกclosedir($s);ก่อนที่}จะแก้ไขขั้นสุดท้าย(+13)
  • จะล้มเหลวหากไดเรกทอรีมีรายการที่ไม่มีชื่อให้ผนวกfalse!==กับเงื่อนไข while เพื่อแก้ไข (+8)

กับ glob, 182 ไบต์ (อาจเป็น 163 ใน 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)."
";}
  • ไม่แสดงหรือเรียกคืนไฟล์ / ไดเรกทอรีที่ซ่อนอยู่
  • 2ย่อมาจากGLOB_MARKจะผนวกเครื่องหมายทับเพื่อชื่อไดเรกทอรีทั้งหมดเช่นเดียวกับls -F
  • preg_replaceหนี glob อักขระพิเศษ
    ฉันจะได้ทำร้ายpreg_quoteสำหรับเรื่องนี้ (-19); แต่นั่นจะล้มเหลวในระบบ Windows เนื่องจากแบ็กสแลชเป็นตัวคั่นไดเรกทอรีที่นั่น
  • php เร็ว ๆ นี้อาจรวมถึงฟังก์ชั่นglob_quoteซึ่งจะช่วยให้การเล่นกอล์ฟเดียวกับpreg_quoteและทำงานได้กับทุกระบบ

ด้วยตัววนซ้ำ, 183 ไบต์
(ดี, ไม่ใช่ตัววนซ้ำอย่างหมดจด: ฉันใช้SplFileInfo::__toString()การเล่นกอล์ฟ$f->getBaseName()และ$f->isDir()ฟังก์ชั่น 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)?"/":"","
";}
  • ไม่ต้องต่อท้ายสแลช
  • แสดงและเรียกซ้ำรายการที่ซ่อนอยู่ ( ls -a)
  • แทรก,4096หรือ,FilesystemIterator::SKIP_DOTSก่อนที่),1จะข้ามรายการจุด (+5) ( ls -A)
  • ธง1ย่อมาจากRecursiveIteratorIterator::SELF_FIRST

0

PowerShell, 147 ไบต์

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

ผู้ชายฉันรู้สึกว่า PS น่าจะทำอะไรได้เหมือนคำตอบทุบตี แต่ฉันไม่ได้คิดอะไรที่สั้นไปกว่าที่ฉันเคยได้รับ

คำอธิบาย:

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

0

Python 2, 138 ไบต์

แก้ไขจากคำตอบ SOนี้ เหล่านี้เป็นแท็บสำหรับการเยื้องไม่ใช่ช่องว่าง "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

ลองออนไลน์ -มันค่อนข้างน่าสนใจที่ฉันได้รับอนุญาตให้เรียกดูไดเรกทอรีบน Ideone ...

ความยาวเท่ากัน:

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

0

รุ่นที่ 237 ไบต์

@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%

โดยที่ \ t แทนอักขระแท็บตัวอักษร รุ่นนี้มีการติดตาม\ในไดเรกทอรี แต่สามารถบันทึกได้ 41 ไบต์หากไม่จำเป็น


ไม่จำเป็นต้องใช้ส่วนท้าย
ASCII-only

0

Perl, 89 ไบต์

มีประโยชน์เมื่อมีโมดูลค้นหาในการแจกแจงหลัก Perl's File :: Find module ไม่ได้สำรวจต้นไม้ตามลำดับตัวอักษร แต่สเป็คไม่ได้ถามสิ่งนั้น

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

สคริปต์ที่เหมาะสมคือ 76 ไบต์ฉันนับ 13 ไบต์สำหรับตัวเลือกบรรทัดคำสั่ง



0

Java 8, 205 ไบต์

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

นี่คือการส่งโปรแกรมแบบเต็มซึ่งรับอินพุตจากอาร์กิวเมนต์บรรทัดคำสั่งแรก (ไม่ได้รับอนุญาตอย่างชัดเจน

ลองใช้ออนไลน์ (หมายเหตุชื่ออินเทอร์เฟซอื่น)

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]), "");
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.