Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive Function to Return Directory Depth of File Tree

Tags:

linux

bash

I'm trying to write a function that will traverse the file directory and give me the value of the deepest directory. I've written the function and it seems like it is going to each directory, but my counter doesn't seem to work at all.

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"
}

What I want it to do is feed the function a directory, say /home, and it'll go down each subdirectory within and find the deepest value. I'm trying to learn recursion better, but I'm not sure what I'm doing wrong.

like image 834
Jef Avatar asked Dec 01 '10 21:12

Jef


5 Answers

Obviously find should be used for this

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

At the end I use awk to just print the output, but if that were the output you wanted it would be better just to echo it that way to begin with.

Not that it helps learn about recursion, of course.

like image 85
sorpigal Avatar answered Oct 26 '22 07:10

sorpigal


Here's a one–liner that's pretty fast:

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

Or as a function:

depth() 
{ 
  find $1 -type d -printf '%d:%p\n' | sort -n | tail -1
}
like image 23
kipkoan Avatar answered Oct 26 '22 09:10

kipkoan


Here is a version that seems to work:

#!/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 "$@"
like image 31
DigitalRoss Avatar answered Oct 26 '22 09:10

DigitalRoss


Just a few small changes to your script. I've added several explanatory comments:

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
}

It prints the max depth (including the starting directory as 1) and the first directory name that it finds at that depth. You can change the test if ((counter > max)) to >= and it will print the last directory name it finds at that depth.

like image 44
Dennis Williamson Avatar answered Oct 26 '22 09:10

Dennis Williamson


The AIX (6.1) find command seems to be quite limited (e.g. no printf option). If you like to list all directories up to a given depth try this combination of find and dirname. Save the script code as maxdepth.ksh. In comparison to the Linux find -maxdepth option, AIX find will not stop at the given maximum level which results in a longer runtime, depending on the size/depth of the scanned direcory:

#!/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

Sample call:

find /usr -type d -exec maxdepth.ksh 2 {} \;
like image 1
Thomas T. Avatar answered Oct 26 '22 09:10

Thomas T.