2010-12-01 80 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 {} \;