2010-12-01 86 views
8

我正在尝试编写一个函数,它将遍历文件目录并给我最深处目录的值。我写了这个函数,看起来好像是要到每个目录,但我的计数器似乎根本不起作用。递归函数返回目录文件树的深度

dir_depth(){ 

local olddir=$PWD 
local dir 
local counter=0 
cd "$1" 


for dir in * 
do 
    if [ -d "$dir" ] 
    then 
    dir_depth "$1/$dir" 
    echo "$dir" 
    counter=$(($counter + 1)) 
    fi 
done 
cd "$olddir" 
} 

我希望它做的是饲料功能的目录,比如/家,它会在每个子目录下去,发现最深的价值。我试图更好地学习递归,但我不确定我做错了什么。

回答

3

这里,似乎工作的一个版本:

#!/bin/sh 

dir_depth() { 
    cd "$1" 
    maxdepth=0 
    for d in */.; do 
    [ -d "$d" ] || continue 
    depth=`dir_depth "$d"` 
    maxdepth=$(($depth > $maxdepth ? $depth : $maxdepth)) 
    done 
    echo $((1 + $maxdepth)) 
} 

dir_depth "[email protected]" 
0

传统的做法是让dir_depth也返回最大深度。所以你会返回名称和深度。

您不能在bash中返回数组,结构或对象,因此您可以返回例如用逗号分隔的字符串代替。

dir_depth(){ 
local dir 

local max_dir="$1" 
local max_depth=0 

for dir in $1/* 
do 
    if [ -d "$dir" ] 
    then 
    cur_ret=$(dir_depth "$dir") 
    cur_depth=$(expr "$cur_ret" : '\([^,]*\)') 
    cur_dir=$(expr "$cur_ret" : '.*,\(.*\)') 
    if [[ "$cur_depth" -gt "$max_depth" ]]; then 
    max_depth="$cur_depth" 
    max_dir="$cur_dir" 
    fi 
    fi 
done 
max_depth=$(($max_depth + 1)) 
echo "$max_depth,$max_dir" 
} 

编辑:现在修复。它从您作为级别1传入的目录开始,然后向上计数。我删除了cd,因为它没有必要。请注意,如果文件名包含逗号,这将失败。

您可能想考虑使用带有更多内置数据结构的编程语言,如Python。

+0

是的,理想情况下,我会用Python来做这件事,但我正在努力学习一下Bash。我需要了解你对expr做了什么,看起来很有趣。谢谢您的帮助! – Jef 2010-12-02 01:25:00

+0

@Jef:Bash有正则表达式匹配,可以用来代替`expr`。 – 2010-12-02 01:57:19

+0

@Jef,我使用[本指南](http://tldp.org/LDP/abs/html/string-manipulation.html)进行字符串操作。 – 2010-12-02 05:07:33

3

只是一些小的改动,以你的脚本。我已经添加了一些解释性评论:

dir_depth(){ 

    # don't need olddir and counter needs to be "global" 
    local dir 
    cd -- "$1" # the -- protects against dirnames that start with - 

    # do this out here because we're counting depth not visits 
    ((counter++)) 

    for dir in * 
    do 
     if [ -d "$dir" ] 
     then 
     # we want to descend from where we are rather than where we started from 
     dir_depth "$dir" 
     fi 
    done 
    if ((counter > max)) 
    then 
     max=$counter  # these are what we're after 
     maxdir=$PWD 
    fi 
    ((counter--)) # decrement and test to see if we're back where we started 
    if ((counter == 0)) 
    then 
     echo $max $maxdir # ta da! 
     unset counter  # ready for the next run 
    else 
     cd .. # go up one level instead of "olddir" 
    fi 
} 

它输出最大深度(包括起始目录中1),它发现在该深度的第一个目录名。您可以将测试if ((counter > max))更改为>=,它将打印它在该深度找到的最后一个目录名称。

8

明显发现应该用于此

find . -type d -exec bash -c 'echo $(tr -cd/<<< "$1"|wc -c):$1' -- {} \; | sort -n | tail -n 1 | awk -F: '{print $1, $2}' 

在我用awk只打印输出的结束,但如果这是你希望它会是更好的输出只是呼应这种方式开始用。

当然,这并不是说它有助于了解递归。

4

这里是一个班轮这是相当快:

find . -type d -printf '%d:%p\n' | sort -n | tail -1 

或者作为一个函数:

depth() 
{ 
    find $1 -type d -printf '%d:%p\n' | sort -n | tail -1 
} 
1

的AIX(6.1)find命令似乎是相当有限的(例如,没有printf的选项) 。如果您想列出所有目录达到给定深度,请尝试使用finddirname的组合。将脚本代码保存为maxdepth.ksh。相较于Linux的发现-maxdepth选项,AIX find在导致一个更长的运行时间,这取决于大小的扫描猪病的/深度给定的最高水平不会停止:

#!/usr/bin/ksh 
# Param 1: maxdepth 
# Param 2: Directoryname 

max_depth=0 
netxt_dir=$2 
while [[ "$netxt_dir" != "/" ]] && [[ "$netxt_dir" != "." ]]; do 
    max_depth=$(($max_depth + 1)) 
    netxt_dir=$(dirname $netxt_dir) 
done 

if [ $1 -lt $max_depth ]; then 
    ret=1 
else 
    ret=0 
    ls -d $2 
fi 
exit $ret 

样品电话:

find /usr -type d -exec maxdepth.ksh 2 {} \;