递归列出Bash中给定目录中的文件

时间:2021-03-06 21:49:17

I know that it can be done using ls -R path. But I'm trying to learn the syntax and control structures of the shell language, so I'm trying to write my own code:

我知道可以使用ls -R路径完成。但我正在尝试学习shell语言的语法和控制结构,所以我正在尝试编写自己的代码:

#!/bin/sh

arg=$1;

lsRec() {
    for x in $1*; do
        if [ -d "$x" ]; then
            lsRec $x;
        else
            echo "$x";
        fi
    done
}

lsRec $arg;

When I call the command ./ej2.sh ~/Documents/, the terminal throws: segmentation fault (core dumped). Why I'm getting this error?, Am I missing something in my code?

当我调用命令./ej2.sh~ / Documents /时,终端抛出:分段错误(核心转储)。为什么我收到此错误?我在代码中遗漏了什么?

Thanks.

3 个解决方案

#1


8  

Your algorithm is entering endless loop since lsRec function implicitly expects its argument to end in "/". First level works, as you pass path ending with "/" as input, but second level doesn't, as the path you're making recursive call with doesn't end in "/". What you could do is either add the slash when you make a recursive call, so it'll look like lsRec $x/, or (better yet) add the slash in the loop arguments as in for x in $1/*; do (as system generally ignores multiple adjacent path separators).

您的算法进入无限循环,因为lsRec函数隐式期望其参数以“/”结尾。第一级工作,因为您传递以“/”结尾的路径作为输入,但第二级不工作,因为您正在进行递归调用的路径不以“/”结尾。你可以做的是在进行递归调用时添加斜杠,所以它看起来像lsRec $ x /,或者(更好的是)在循环参数中添加斜杠,就像在$ 1 / *中的x一样; do(因为系统通常忽略多个相邻的路径分隔符)。

Moving forward, I'd advise you to quote the values (e.g. for x in "$1/"*, lsRec "$x", lsRec "$arg") to avoid issues when path contains whitespace characters. You'll get there when you create a directory with space in its name under directory hierarchy you're scanning.

继续前进,我建议你引用值(例如,对于“$ 1 /”*,lsRec“$ x”,lsRec“$ arg”中的x),以避免路径包含空格字符时出现问题。当您在扫描的目录层次结构下创建名称中包含空格的目录时,您将到达那里。

#2


4  

The problem here is that "for x in $1*" finds $1, if that makes sense? So it becomes an infinite loop. There are two solutions:

这里的问题是“for $ in $ 1 *”找到$ 1,如果这有意义的话?所以它变成了无限循环。有两种解决方案:

  • Check if x == $1
  • 检查x == $ 1

  • Change the for loop to "for x in $1/*"
  • 将for循环更改为“for $ in $ 1 / *”

Because $1 is replaced by the argument passed to the function right? So if it sends "hello" then it becomes "for x in hello*". Now, that is a globbing pattern and will select "hello" and thus an infinite loop.

因为$ 1被传递给函数的参数替换了吗?因此,如果它发送“hello”,那么它变为“for hello *”。现在,这是一个通配模式,将选择“你好”,因此是一个无限循环。

The second solution works because "hello" becomes "hello/*" instead of "hello*".

第二个解决方案有效,因为“hello”变为“hello / *”而不是“hello *”。

This code works fine for me:

这段代码对我来说很好:

#!/bin/sh

arg=$1;

lsRec() {
    for x in "$1"/*; do
        echo "$x"
        if [ -d "$x" ]; then
            echo "This is a directory:"
            lsRec "$x";
        else
            echo "This is not a directory:"
            echo "$x";
       fi
    done
}

lsRec "$arg";

Hope it helps!

希望能帮助到你!

#3


2  

I think you created a fork bomb. Your code creates an infinite recursion.

我想你创造了一个叉炸弹。您的代码创建无限递归。

You should change the code to:

您应该将代码更改为:

#!/bin/sh
   arg=$1;

   lsRec() {
      for x in $1/*; do
        if [ -d "$x" ]; then
            echo "$x"  ## here you print the line
            lsRec $x; ## here you pass the contents and NOT the line itself
                        ## your programm was passing dirs without processing
                        ## over and over
        else
            echo "$x";
        fi
    done
}

lsRec $arg;

#1


8  

Your algorithm is entering endless loop since lsRec function implicitly expects its argument to end in "/". First level works, as you pass path ending with "/" as input, but second level doesn't, as the path you're making recursive call with doesn't end in "/". What you could do is either add the slash when you make a recursive call, so it'll look like lsRec $x/, or (better yet) add the slash in the loop arguments as in for x in $1/*; do (as system generally ignores multiple adjacent path separators).

您的算法进入无限循环,因为lsRec函数隐式期望其参数以“/”结尾。第一级工作,因为您传递以“/”结尾的路径作为输入,但第二级不工作,因为您正在进行递归调用的路径不以“/”结尾。你可以做的是在进行递归调用时添加斜杠,所以它看起来像lsRec $ x /,或者(更好的是)在循环参数中添加斜杠,就像在$ 1 / *中的x一样; do(因为系统通常忽略多个相邻的路径分隔符)。

Moving forward, I'd advise you to quote the values (e.g. for x in "$1/"*, lsRec "$x", lsRec "$arg") to avoid issues when path contains whitespace characters. You'll get there when you create a directory with space in its name under directory hierarchy you're scanning.

继续前进,我建议你引用值(例如,对于“$ 1 /”*,lsRec“$ x”,lsRec“$ arg”中的x),以避免路径包含空格字符时出现问题。当您在扫描的目录层次结构下创建名称中包含空格的目录时,您将到达那里。

#2


4  

The problem here is that "for x in $1*" finds $1, if that makes sense? So it becomes an infinite loop. There are two solutions:

这里的问题是“for $ in $ 1 *”找到$ 1,如果这有意义的话?所以它变成了无限循环。有两种解决方案:

  • Check if x == $1
  • 检查x == $ 1

  • Change the for loop to "for x in $1/*"
  • 将for循环更改为“for $ in $ 1 / *”

Because $1 is replaced by the argument passed to the function right? So if it sends "hello" then it becomes "for x in hello*". Now, that is a globbing pattern and will select "hello" and thus an infinite loop.

因为$ 1被传递给函数的参数替换了吗?因此,如果它发送“hello”,那么它变为“for hello *”。现在,这是一个通配模式,将选择“你好”,因此是一个无限循环。

The second solution works because "hello" becomes "hello/*" instead of "hello*".

第二个解决方案有效,因为“hello”变为“hello / *”而不是“hello *”。

This code works fine for me:

这段代码对我来说很好:

#!/bin/sh

arg=$1;

lsRec() {
    for x in "$1"/*; do
        echo "$x"
        if [ -d "$x" ]; then
            echo "This is a directory:"
            lsRec "$x";
        else
            echo "This is not a directory:"
            echo "$x";
       fi
    done
}

lsRec "$arg";

Hope it helps!

希望能帮助到你!

#3


2  

I think you created a fork bomb. Your code creates an infinite recursion.

我想你创造了一个叉炸弹。您的代码创建无限递归。

You should change the code to:

您应该将代码更改为:

#!/bin/sh
   arg=$1;

   lsRec() {
      for x in $1/*; do
        if [ -d "$x" ]; then
            echo "$x"  ## here you print the line
            lsRec $x; ## here you pass the contents and NOT the line itself
                        ## your programm was passing dirs without processing
                        ## over and over
        else
            echo "$x";
        fi
    done
}

lsRec $arg;