【问题标题】:Linux command to print directory structure in the form of a treeLinux命令以树的形式打印目录结构
【发布时间】:2011-03-28 04:54:55
【问题描述】:

是否有任何我可以从 Bash 脚本调用的 linux 命令,它将以树的形式打印目录结构,例如,

folder1
   a.txt
   b.txt
folder2
   folder3

【问题讨论】:

  • 运行find。或find . -not -path '*/\.*' 隐藏以. 开头的文件和文件夹。如果您想在问题中输出带有空格的输出,请将其与此“查找美化器”脚本一起使用:find . -not -path '*/\.*' | python -c "import sys as s;s.a=[];[setattr(s,'a',list(filter(lambda p: c.startswith(p+'/'),s.a)))or (s.stdout.write(' '*len(s.a)+c[len(s.a[-1])+1 if s.a else 0:])or True) and s.a.append(c[:-1]) for c in s.stdin]"
  • 这样的问题不应该被迁移到超级用户而不是关闭吗?
  • 我认为这个问题不应该作为“离题”来结束。标签似乎是正确的。
  • 在不迁移的情况下关闭问题的策略总体上对 stackoverflow 和人类知识都是有害的。在过去的 3 天里,我在谷歌上搜索到的每一个问题都因为类似的原因而被关闭,并且没有更多的活动能够发生。这意味着没有人可以更新它,没有人可以给出更好的答案,并且它使 stackoverflow 看起来短视或精英主义。当发现某个主题具有这些条件时,Stackoverflow 应该考虑要求迁移。
  • 我同意@NickYeates 的观点,我在 2017 年 9 月下旬来到这里,仍在寻找同样问题的答案。我们在设计这些问答政策时要着眼长远!

标签: linux command-line


【解决方案1】:

这就是你要找的tree吗?它应该在大多数发行版中(可能作为可选安装)。

~> tree -d /proc/self/
/proc/self/
|-- attr
|-- cwd -> /proc
|-- fd
|   `-- 3 -> /proc/15589/fd
|-- fdinfo
|-- net
|   |-- dev_snmp6
|   |-- netfilter
|   |-- rpc
|   |   |-- auth.rpcsec.context
|   |   |-- auth.rpcsec.init
|   |   |-- auth.unix.gid
|   |   |-- auth.unix.ip
|   |   |-- nfs4.idtoname
|   |   |-- nfs4.nametoid
|   |   |-- nfsd.export
|   |   `-- nfsd.fh
|   `-- stat
|-- root -> /
`-- task
    `-- 15589
        |-- attr
        |-- cwd -> /proc
        |-- fd
        | `-- 3 -> /proc/15589/task/15589/fd
        |-- fdinfo
        `-- root -> /

27 directories

样本取自维护者的网页。

您可以添加选项-L #,其中# 替换为数字,以指定最大递归深度。

删除 -d 以同时显示文件。

【讨论】:

  • 任何看到此内容的访问者请注意:删除 -d 以同时显示文件!
  • 任何看到此内容的访问者请注意:手册页为您列出了一卡车更多标志:)
  • 在 Mac OS X 上安装 Homebrew:brew install tree
  • 在cygwin上安装apt-cyg install tree(假设你已经安装了apt-cyg)
  • 甚至 Ubuntu 16.04 都没有。使用apt-get install tree 会安装它。
【解决方案2】:

你可以用这个:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'

它将在几秒钟内显示当前没有文件的子目录的图形表示,例如在 /var/cache/:

   .
   |-apache2
   |---mod_cache_disk
   |-apparmor
   |-apt
   |---archives
   |-----partial
   |-apt-xapian-index
   |---index.1
   |-dbconfig-common
   |---backups
   |-debconf

Source

【讨论】:

  • 如果你想要空格,更像是 OP 要求的,那么这个:ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\// /g' -e 's/^/ /'
  • 有什么方法可以让这个忽略点文件?例如。阻止它列出.git的内容?
  • 带文件:find . | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/"
  • @Ben 谢谢你,所有其他(非tree)答案产生的结果对我来说看起来并不完全正确。例如,在这个答案中,应该有一条线从apt 下降到水平线到archives,而不是从. 下降到archives,只是因为更多的缩进你可以猜到它实际上是apt 的子文件夹。所以你也可以把这些线放在一边,这样至少不会误导。
  • @JavaSheriff 你的很棒
【解决方案3】:

此命令用于同时显示文件夹和文件

find . | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/"

示例输出:

.
 |-trace.pcap
 |-parent
 | |-chdir1
 | | |-file1.txt
 | |-chdir2
 | | |-file2.txt
 | | |-file3.sh
 |-tmp
 | |-json-c-0.11-4.el7_0.x86_64.rpm

来源:来自@javasheriff here 的评论。将其作为评论淹没并将其作为答案发布有助于用户轻松发现它。

【讨论】:

  • 对于 python3,我发现 find . |grep -vE 'pyc|swp|__init' | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/" 运行良好
  • 这是一个很大的帮助,因为我们没有在某个服务器上安装树。这很可能适用于任何标准 Linux 系统。
【解决方案4】:

由于这是一条成功的评论,我将其添加为答案:
要以树的形式打印目录结构,
WITH FILES

 find . | sed -e "s/[^-][^\/]*\//  |/g" -e "s/|\([^ ]\)/|-\1/" 

【讨论】:

  • 如果您想对结果列表进行排序,然后将上面的好解决方案与sort 结合起来:find . | sort | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/"
【解决方案5】:

要将 Hassou 的解决方案添加到您的 .bashrc,请尝试:

alias lst='ls -R | grep ":$" | sed -e '"'"'s/:$//'"'"' -e '"'"'s/[^-][^\/]*\//--/g'"'"' -e '"'"'s/^/   /'"'"' -e '"'"'s/-/|/'"'"

【讨论】:

  • 如果直接复制,请注意第一行末尾的换行符
  • 不错的别名。但最后缺少 ' ' (2 个单引号字符)。即使没有它,它也可以工作,但是......如果你想在最后添加更多命令,你会看到文字不完整。所以它应该去alias lst='ls -R | grep ":$" | sed -e '"'"'s/:$//'"'"' -e '"'"'s/[^-][^\/]*\//--/g'"'"' -e '"'"'s/^/ /'"'"' -e '"'"'s/-/|/'"'"''
【解决方案6】:

由于我对其他(非tree)答案的输出不太满意(请参阅my comment at Hassou's answer),因此我尝试更多地模仿trees 的输出。

这与罗伯特的答案相似,但水平线并非都从开头开始,而是应该从哪里开始。虽然必须使用perl,但在我的情况下,在我没有tree 的系统上,perl 可用。

ls -aR | grep ":$" | perl -pe 's/:$//;s/[^-][^\/]*\//    /g;s/^    (\S)/└── \1/;s/(^    |    (?= ))/│   /g;s/    (\S)/└── \1/'

输出(缩短):

.
└── fd
└── net
│   └── dev_snmp6
│   └── nfsfs
│   └── rpc
│   │   └── auth.unix.ip
│   └── stat
│   └── vlan
└── ns
└── task
│   └── 1310
│   │   └── net
│   │   │   └── dev_snmp6
│   │   │   └── rpc
│   │   │   │   └── auth.unix.gid
│   │   │   │   └── auth.unix.ip
│   │   │   └── stat
│   │   │   └── vlan
│   │   └── ns

欢迎提出避免多余垂直线的建议 :-)

我仍然非常喜欢 Hassou 回答的评论中的 Ben's solution,没有(不完全正确的)行会更干净。对于我的用例,我还删除了全局缩进并添加了ls隐藏文件的选项,如下所示:

ls -aR | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//  /g'

输出(进一步缩短):

.
  fd
  net
    dev_snmp6
    nfsfs
    rpc
      auth.unix.ip
    stat
    vlan
  ns

【讨论】:

  • 在处理ls -R 的输出时摆脱不需要的垂直线的唯一方法是从最后一行继续到第一行。请参阅我提供的基于 awk 的解决方案,您可以轻松适应 perl。
【解决方案7】:

我正在美化@Hassou 回答的输出:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//──/g' -e 's/─/├/' -e '$s/├/└/'

这很像tree now 的输出:

.
├─pkcs11
├─pki
├───ca-trust
├─────extracted
├───────java
├───────openssl
├───────pem
├─────source
├───────anchors
├─profile.d
└─ssh

你也可以给它起一个别名:

alias ltree=$'ls -R | grep ":$" | sed -e \'s/:$//\' -e \'s/[^-][^\/]*\//──/g\' -e \'s/─/├/\' -e \'$s/├/└/\''

顺便说一句,tree 在某些环境中不可用,例如 MinGW。所以备用是有帮助的。

【讨论】:

  • windows上的gitbash不喜欢最后一个表达式,它说它没有终止
  • @LeosLiterak:在 Windows 上,本机 tree 应该可以通过命令提示符 (cmd) 或 PowerShell 使用 :-)
【解决方案8】:

在 bashrc 中添加以下函数可让您运行不带任何参数的命令,该命令显示当前目录结构,并且当使用任何路径作为参数运行时,将显示该路径的目录结构。这避免了在运行命令之前切换到特定目录的需要。

function tree() {
    find ${1:-.} | sed -e "s/[^-][^\/]*\//  |/g" -e "s/|\([^ ]\)/|-\1/"
}

这也适用于 gitbash。

来源:@javasheriff here的评论

【讨论】:

    【解决方案9】:

    您还可以结合使用 find 和 awk 命令来打印目录树。详情请参考“How to print a multilevel tree directory structure using the linux find and awk combined commands

    find . -type d | awk -F'/' '{ 
    depth=3;
    offset=2;
    str="|  ";
    path="";
    if(NF >= 2 && NF < depth + offset) {
        while(offset < NF) {
            path = path "|  ";
            offset ++;
        }
        print path "|-- "$NF;
    }}'
    

    【讨论】:

      【解决方案10】:

      最好的答案当然是树。但是,为了改进依赖于 grepping ls -R 的输出的其他答案,这里是一个使用 awk 打印子目录树的 shell 脚本。一、输出示例:

      . └── 匹配 ├── 围兜 ├── 数据 │ └── 来源 │ └── html ├── 数据 │ └── 地块 ├── 方法 │ ├── 信息 │ └── 软 │ ├── imgs │ │ ├── ascii │ │ └── 符号 │ └── js └── 毫秒

      然后,代码:

      ls -qLR 2>/dev/null \
      | grep '^./' \
      | sed -e 's,:$,,' \
      | awk '
          function tip(new) { stem = substr(stem, 1, length(stem) - 4) new }
          {
              path[NR] = $0
          }
          END {
              elbow = "└── "; pipe = "│   "; tee = "├── "; blank = "    "
              none = ""
              #
              # Model each stem on the previous one, going bottom up.
              for (row = NR; row > 0; row--) {
                  #
                  # gsub: count (and clean) all slash-ending components; hence,
                  # reduce path to its last component.
                  growth = gsub(/[^/]+\//, "", path[row]) - slashes
                  if (growth == 0) {
                      tip(tee)
                  }
                  else if (growth > 0) {
                      if (stem) tip(pipe) # if...: stem is empty at first!
                      for (d = 1; d < growth; d++) stem = stem blank
                      stem = stem elbow
                  }
                  else {
                      tip(none)
                      below = substr(stem, length(stem) - 4, 4)
                      if (below == blank) tip(elbow); else tip(tee)
                  }
                  path[row] = stem path[row]
                  slashes += growth
              }
              root = "."; print root
              for (row = 1; row <= NR; row++) print path[row]
          }
      '
      

      该代码提供的结果比其他解决方案更好看,因为在子目录树中,任何分支中的装饰都依赖于它下面的分支。因此,我们需要以相反的顺序处理ls -R 的输出,从最后一行到第一行。

      可以在这里找到基于此代码的 shell 函数(带有一些选项):

      https://github.com/ftonneau/t.sh

      【讨论】:

        猜你喜欢
        • 2015-10-15
        • 2016-08-14
        • 1970-01-01
        • 2016-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多