Рекурсивная функция для возврата каталога глубины дерева файлов - PullRequest
8 голосов
/ 02 декабря 2010

Я пытаюсь написать функцию, которая будет проходить через каталог файлов и давать мне значение самого глубокого каталога. Я написал функцию, и похоже, что она идет в каждый каталог, но мой счетчик, похоже, не работает вообще.

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

То, что я хочу сделать, это передать функции каталог, скажем / home, и он пойдет по каждому подкаталогу внутри и найдет самое глубокое значение. Я пытаюсь научиться рекурсии лучше, но я не уверен, что делаю неправильно.

Ответы [ 6 ]

8 голосов
/ 02 декабря 2010

Очевидно, для этого нужно использовать find

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 голосов
/ 17 марта 2012

Вот одна строчка, которая довольно быстрая:

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

Или как функция:

depth() 
{ 
  find $1 -type d -printf '%d:%p\n' | sort -n | tail -1
}
3 голосов
/ 02 декабря 2010

Всего несколько небольших изменений в вашем скрипте.Я добавил несколько пояснительных комментариев:

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)) на >=, и он напечатает последнее имя каталога, найденное на этой глубине.

3 голосов
/ 02 декабря 2010

Вот версия, которая работает:

#!/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 "$@"
1 голос
/ 17 марта 2015

Команда AIX (6.1) find выглядит довольно ограниченной (например, нет опции printf). Если вы хотите перечислить все каталоги до заданной глубины, попробуйте эту комбинацию find и dirname. Сохраните код скрипта как maxdepth.ksh. По сравнению с опцией Linux find -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 {} \;
0 голосов
/ 02 декабря 2010

Традиционный способ сделать это - 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...