如何在不使用"find"或"ls"命令的情况下递归列出Bash中的子目录?

Rag*_*ani 11 bash

我知道你可以使用这个find命令完成这个简单的工作,但我得到了一个不使用findls完成工作的任务.我怎样才能做到这一点?

gho*_*g74 30

你可以只使用shell来做到这一点

#!/bin/bash
recurse() {
 for i in "$1"/*;do
    if [ -d "$i" ];then
        echo "dir: $i"
        recurse "$i"
    elif [ -f "$i" ]; then
        echo "file: $i"
    fi
 done
}

recurse /path
Run Code Online (Sandbox Code Playgroud)

或者如果你有bash 4.0

#!/bin/bash
shopt -s globstar
for file in /path/**
do
    echo $file
done
Run Code Online (Sandbox Code Playgroud)


Alb*_*gni 11

尝试使用

tree -d
Run Code Online (Sandbox Code Playgroud)

  • @Vlad Romascanu:哦......好吧,但是从"我得到的任务不使用find或ls并完成工作"我明白一切都很好,除了找到和ls ^^ (7认同)
  • 我没有给你 -1,但我很清楚你为什么得到它。为什么不给出答案`alias bla ls ; 布拉`?被问到的问题是编写算法,而不是找到一些与 `ls` 做同样事情但不称为 `ls` 的 *command*。 (2认同)

vla*_*adr 5

以下是一种可能的实现:

# my_ls -- recursively list given directory's contents and subdirectories
# $1=directory whose contents to list
# $2=indentation when listing
my_ls() {
  # save current directory then cd to "$1"
  pushd "$1" >/dev/null
  # for each non-hidden (i.e. not starting with .) file/directory...
  for file in * ; do
    # print file/direcotry name if it really exists...
    test -e "$file" && echo "$2$file"
    # if directory, go down and list directory contents too
    test -d "$file" && my_ls "$file" "$2  "
  done
  # restore directory
  popd >/dev/null
}

# recursively list files in current
#  directory and subdirectories
my_ls .
Run Code Online (Sandbox Code Playgroud)

作为练习,你可以想到如何修改上面的脚本来打印文件的完整路径(而不仅仅是缩进的文件/ dirnames),可能在过程中摆脱pushd/ popd(以及第二个参数的需要$2).

顺便提一下,请注意其使用test XYZ && command完全等同于if test XYZ ; then command ; fi(即,command如果test XYZ成功则执行).还要注意test XYZ相当于[ XYZ ],即上面也相当于if [ XYZ ] ; then command ; fi.另请注意,任何分号;都可以用换行符替换,它们是等效的.

删除test -e "$file" &&条件(只留下echo),看看会发生什么.

删除双引号"$file",看看当你列出的内容包含带空格的文件名时会发生什么.set -x在脚本的顶部添加(或者sh -x scriptname.sh相反地调用它)以打开调试输出并查看详细信息(将调试输出重定向到文件,运行sh -x scriptname.sh 2>debugoutput.txt).

要列出隐藏文件(例如.bashrc):

...
for file in * .?* ; do
  if [ "$file" != ".." ] ; then
    test -e ...
    test -d ...
  fi
done
...
Run Code Online (Sandbox Code Playgroud)

注意使用!=(字符串比较)而不是-ne(数字比较).

另一种技术是产生子壳而不是使用pushd/ popd:

my_ls() {
  # everything in between roundbrackets runs in a separatly spawned sub-shell
  (
    # change directory in sub-shell; does not affect parent shell's cwd
    cd "$1"
    for file in ...
      ...
    done
  )
}
Run Code Online (Sandbox Code Playgroud)

请注意,在某些shell实现上,对于可以作为参数传递的字符数for(或者对于任何内置命令或外部命令),存在硬限制(~4k).由于shell 扩展,内联,*在实际执行之前所有匹配的文件名的列表,for如果*在包含大量文件的目录中扩展,则会遇到麻烦(运行时会遇到同样的问题,比如ls *在同一目录中,例如得到类似的错误)Command too long.)


小智 5

由于它是针对 bash 的,所以令人惊讶的是,这还没有被提及:
(globstar 从 bash 4.0+ 起有效)

shopt -s globstar nullglob dotglob
echo **/*/
Run Code Online (Sandbox Code Playgroud)

就这样。
尾部斜杠/仅用于选择目录。

选项globstar激活**(递归搜索)。选项在不匹配任何文件/目录时nullglob删除 an 。*选项dotglob包括以点开头的文件(隐藏文件)。


pav*_*ium 1

du命令将递归地列出子目录。

不过,我不确定目录是否会被提及