【问题标题】:Directory depth in recursive script递归脚本中的目录深度
【发布时间】:2018-04-26 07:12:03
【问题描述】:

嗨,我想在我的 linux bash 作业上获得一些帮助。 我必须制作一个脚本来获取目录并返回最深子目录的深度(每个目录+1)。 我必须递归地做。 我必须使用“list_dirs.sh”来获取病毒目录并回显其子目录。

这就是我目前得到的:

dir=$1
sub=`source list_dirs.sh`

((depth++)) 

for i in $sub
do
  if [ -n "$sub" ] ; then
      ./depthScript $dir/$i
  fi
done

if ((depth > max)) ; then
   max=$depth
   echo $max
fi

在使用假设返回 3 的目录进行测试后,我得到了安装:

1
1
1
1

似乎我的深度计数器忘记了以前的值,我得到了输出 每个目录..需要一些帮助!

【问题讨论】:

  • 您可以将其作为参数传递给脚本,而不是全局变量。
  • 但是为什么在我的脚本中深度被认为是局部的而不是全局的?它是如何工作的?我认为我不允许以任何方式更改仅 dir 的脚本的输入

标签: linux bash shell


【解决方案1】:

您可以使用bash functions 创建递归函数调用。

理想情况下,您的函数将在没有子目录的目录上调用它的基本情况下回显0,并在存在某些子目录$subdir 的情况下回显1+$(getDepth $subdir)。有关框架,请参阅 this question on recursive functions in bash

【讨论】:

    【解决方案2】:

    当您正常运行脚本时(即它在您的PATH 中并且您只需输入它的名称,或者您输入它的显式路径,如 ./depthScript),它会作为当前 shell 的子进程运行。这很重要,因为每个进程都有自己的变量。变量也有两种:shell 变量(仅在该进程中可用)和环境变量(其值被导出到子进程但不从它们备份)。根据您希望变量值可用的位置,可以使用三种不同的方式来定义它们:

    # By default, variables are shell variable that's only defined in this process:
    shellvar=something
    
    # `export` puts a variable into the environment, so it'll be be exported to subprocesses.
    # You can export a variable either while setting it, or as a separate operation:
    export envvar=something
    export anotherenvvar
    anotherenvvar=something
    
    # You can also prefix a command with a variable assignment. This makes an
    # environment variable in the command process's environment, but not the current
    # shell process's environment:
    prefixvar=something ./depthScript $dir/$i
    

    鉴于上述任务:

    • shellvar 定义在当前 shell 进程中,但不在任何其他进程中(包括为运行 depthScript 而创建的子进程)。
    • envvaranotherenvvar 将被子进程(及其子进程,以及后续命令的所有子进程)继承,但在这些子进程中对其所做的任何更改对当前进程都没有任何影响。
    • prefixvar在为运行 depthScript(及其子进程)而创建的子进程中可用,但在当前 shell 进程或其任何其他子进程中不可用。

    简短的总结:由于流程结构,这很混乱,因此最好避免尝试在变量中的脚本(或同一脚本的不同调用)之间传递值。使用环境变量进行设置,以便您希望普遍可用(但不需要进行太多更改)。将 shell 变量用于特定脚本调用的本地内容。

    那么,你应该如何传递深度值呢?好吧,标准的方法是让每个脚本(或命令)将其输出打印到“标准输出”,然后使用该脚本的任何内容都可以将其输出捕获到文件(command >outfile)或变量(var=$(command)) .在这种情况下,我会推荐后者:

    depth=$(./depthScript "$dir/$i")
    if ((depth > max)) ; then
        max=$depth
    fi
    

    其他一些建议:

    • 认为您的控制和数据流过。当前脚本循环遍历所有子目录,然后在最后运行一次检查最深的子目录。但是您需要单独检查每个子目录,看看它是否比当前最大值更深,最后报告其中最深的一个。
    • 双引号引用您的变量引用(就像我在上面对"$dir/$i" 所做的那样)。未加引号的变量引用会受到分词和通配符扩展的影响,这是令人悲痛的根源。看起来您需要将 $sub 不加引号,因为您需要将其拆分为单词,但这会使脚本无法处理带有空格的目录名称。见BashFAQ #20: "How can I find and safely handle file names containing newlines, spaces or both?"
    • if [ -n "$sub" ] ; then 测试无关紧要。如果$sub 为空,则循环永远不会运行。
    • 在 shell 脚本中,相对路径(如 ./depthScript)相对于父进程的工作目录,相对于脚本的位置。如果有人从另一个目录运行您的脚本,./depthScript 将不起作用。请改用"$BASH_SOURCE"。见BashFAQ #28: "How do I determine the location of my script? I want to read some config files from the same place."
    • 在尝试对脚本进行故障排除时,将set -x 放在有问题的部分之前会有所帮助。这会使 shell 在运行时打印每个命令,以便您查看发生了什么。
    • 通过shellcheck.net 运行您的脚本——它会指出很多常见错误。

    【讨论】: