递归函数不起作用

递归函数不起作用

我知道这是一个荒谬的想法,但我正在尝试让脚本能够分支到文件系统上的每个目录。该文件的名称是“Everywhere.sh”。这是代码:

#!/bin/bash

recurse(){
    cd $1   
    for INDEX in $(echo *)
    do
        recurse $INDEX
    done
}

recurse /

我该如何更改它(除了 su root -c "./Everywhere.sh")以使其正常工作?

编辑:我只需要修复这个问题;我不需要不同的执行方法。

答案1

(你的问题似乎已经得到了回答;我想解决它的另一个方面。)

尽管您说“我知道这很荒谬”,但我只想提一下,在文件系统上的每个目录中运行某些命令可以通过以下命令完成:

find / -type d -exec sh -c 'cd "$1" && some_command' sh {} \;

这不会解决您的权限问题,但它比编写递归 shell 函数简单得多。

答案2

原始脚本的主要问题之一是它发生了变化进入目录,但永远不会退出它们。

recurse ()
(
  recurse2 ()
  {
    [ $_recurse_stop -eq 1 ] && return
    cd "./$1" || return
    pwd ## do whatever you want in the pwd
    for entry in * .*;
    do
        [ "." = "$entry" -o ".." = "$entry" ] && continue;
        [ -d "$entry" -a ! -h "$entry" ] && recurse2 "$entry";
    done
    cd ..
  }

  _recurse_stop=0
  trap '_recurse_stop=1' 2
  recurse2 "$1"
)

另一个变化是替换$(echo *)为简单的*glob。

我还进行了简单的修复,仅尝试递归目录(-d测试)。

在@Wildcard 和 @mikeserv 提出了几条深刻的评论后,此脚本现在:

  • 创建一个顶级子 shell 来隔离cd周围的所有 ing,
  • 拒绝cd进入符号链接目录 ( ! -h),并且
  • 如果收到^C(中断)信号,则设置一个陷阱以停止递归(通过信号变量)

答案3

简单的例子:

cdtree()
    if    OLDPWD=${1-.} cd -P - &&
          set . ./.[!.]*/ ./..?*/ ./*/ "" "${1%"${1#.}"}."
    then  while [ "${1:+1}" ]   && shift
          do    [ ! -d "$1" -o  -h "${1%/}" ]|| cdtree "$1"
          done; cd  -P "$2"
    else  printf %s\\n "$PWD/${1#./}"
    fi

它处理.以前导点命名的目录,它拒绝遵循符号链接,并做出合理的尝试将 shell 的当前工作目录恢复到启动它的目录。

它忽略除第一个参数之外的所有参数,否则如果不带参数调用,它将递归以 为根的树.

它有能力:

{    find / -type d | wc -l
     cdtree /       | wc -l
}    2>/dev/null

23928
23928

而且相当快。find在大约 0.6 秒内遍历我的根树。1.6 秒内完成cdtree()dash这与旧版本的完成时间基本相同。旧版本bash的运行时间令人难以忍受——大约是 的 20 倍dash。经过这个编辑,它的时间不到 5 秒,所以是可以忍受的,但仍然是一条狗。实在是搞不懂bash人气。

实际例子:

cdtree()
    if    OLDPWD=${1-.} cd -P - &&
          "${cd_tree_callback-:}" "$PWD" &&
          set . ./.[!.]*/ ./..?*/ ./*/ "" "${1%"${1#.}"}."
    then  while [ "${1:+1}" ]   && shift
          do    [ ! -d "$1" -o  -h "${1%/}" ]|| cdtree "$1"
          done; cd  -P "$2"
    else  printf %s\\n "$PWD/${1#./}"
    fi

因为我认为人们可能想要在当前 shell 进程中做这样的事情的唯一原因是以某种方式影响当前 shell 状态,或者为每个目录运行一些当前 shell 特定的命令 - 该示例使其实际上成为可能。

如果$cd_tree_callback设置为某个命令的名称,它将针对每个cd_tree可以直接更改为的目录运行。如果当前工作目录因此而更改,上面的内容可能会变得很奇怪 - 但这只是一个警告,您应该做您喜欢的事情。否则的话,如果是未设置回调是一个无操作,如果设置但为空,或者不是一个有效的命令,或者如果调用的命令返回 false,则树递归在该点被切断,并且只有目录名称在该级别之前打印到 stdout树递归返回到前一个。

可以将其视为'和原语cd_tree_callback的组合。find-exec-prune

还有非常递归的例子...

cdtree(){
        set '
#       \eval " \shift 0${3+1};'\
'               $1$1\\${1##* } \"\$PWD\" \"\$@\";'\
'       \eval   \"\${1#??}\";}; return"
        cdtree()
                if      OLDPWD=${1%/}   \cd -P -
                then    for  d  in      ./.[!.]*/ ./..?*/ ./*/
                        do      \[ ! -d "$d" -o -h "${d%/}" ] ||
                                \cdtree "${PWD%/}/${d#?/}" "$PWD"
                        done;   \cd -P  "${2:-.}"
                else    \printf %s\\n   "${PWD%/}/${1#?/}"
                fi
        while   \[  "${2+1}"  ] &&  \shift
        do      \[ "${1##/*}" ] &&  \set -- "$PWD$@"
                \[  / = "$1"  ] &&  \set -- "/$@"
                d=   \command eval "\cdtree \"\$1\" \"\$PWD\""
        done
        cdtree(){ \set '\' "$PWD" "$@"
        eval "${1#??}"
}

我忘记了当一个程序可以在运行时完全重现其自己的源代码时它叫什么......有一个名称,但是......它逃脱了我。无论如何,事情就是这样的。首先,它基本上保存了函数的整个主体,然后,使用该值定义了一个新cdtree()函数,可以在while循环中为每个参数调用该函数。所以你可以给它尽可能多的参数,它会为每个参数完全递归树。当所有这些完成后,它会再次将自身重新定义为原始状态,以便下次调用它时它会执行相同的操作。

显然这是一种奎因...不过,这并没有将其源代码打印到输出中,而是评估它,更改它,然后重现并恢复它。

相关内容