Глубина каталогов в рекурсивном скрипте - PullRequest
0 голосов
/ 25 апреля 2018

привет, я хотел бы получить некоторую помощь с домашними заданиями по Linux.Я должен сделать скрипт, который получает каталог и возвращает глубину самого глубокого подкаталога (+1 для каждого каталога).Я должен сделать это рекурсивно.Я должен использовать 'list_dirs.sh', который принимает viable dir и отображает его subdirs.

вот что я получил до сих пор:

dir=$1
sub=`source list_dirs.sh`

((depth++)) 

for i in $sub
do
  if [ -n "$sub" ] ; then
      ./depthScript $dir/$i
  fi
done

if ((depth > max)) ; then
   max=$depth
   echo $max
fi

после тестирования с dir, который может вернуть 3Я получил:

1
1
1
1

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

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Когда вы запускаете скрипт в обычном режиме (т. Е. Он находится в вашем PATH и вы просто вводите его имя или вы указываете явный путь к нему, например ./depthScript), он запускается как подпроцесс текущей оболочки. Это важно, потому что у каждого процесса есть свои переменные. Переменные также бывают двух видов: переменные оболочки (которые доступны только в этом одном процессе) и переменные среды (значения которых экспортируются в подпроцессы, но не копируются из них). И в зависимости от того, где вы хотите, чтобы значение переменной было доступно, есть три различных способа их определения:

# By default, variables are shell variable that's only defined in this process:
shellvar=something

# `export` puts a variable into the environment, so it'll be be exported to subprocesses.
# You can export a variable either while setting it, or as a separate operation:
export envvar=something
export anotherenvvar
anotherenvvar=something

# You can also prefix a command with a variable assignment. This makes an
# environment variable in the command process's environment, but not the current
# shell process's environment:
prefixvar=something ./depthScript $dir/$i

С учетом вышеуказанных заданий:

  • shellvar определено в текущем процессе оболочки, но не в любом другом процессе (включая подпроцесс, созданный для запуска глубины скрипта).
  • envvar и anotherenvvar будут унаследованы подпроцессом (и его подпроцессами, и всеми подпроцессами для более поздних команд), но любые изменения, внесенные в него в этих подпроцессах, вообще не влияют на текущий процесс.
  • prefixvar доступно только в подпроцессе, созданном для запуска глубинного скрипта (и его подпроцессов), но не в текущем процессе оболочки или любых других его подпроцессах.

Краткое резюме: это беспорядок из-за структуры процесса, и в результате лучше всего избегать даже попыток передавать значения между сценариями (или различными вызовами одного и того же сценария) в переменных. Используйте переменные окружения для настроек и такие, которые вы хотите быть общедоступными (но не нужно сильно менять). Используйте переменные оболочки для вещей, локальных для определенного вызова скрипта.

Итак, как вы должны передавать значения глубины? Ну, стандартный способ - для каждого скрипта (или команды) выводить свои выходные данные в «стандартный вывод», и тогда все, что использует скрипт, может записывать свои выходные данные либо в файл (command >outfile), либо в переменную (var=$(command)) , Я бы порекомендовал последнее в этом случае:

depth=$(./depthScript "$dir/$i")
if ((depth > max)) ; then
    max=$depth
fi

Некоторые другие рекомендации:

  • Подумайте о своем контроле и потоке данных. Текущий скрипт проходит по всем подкаталогам, а затем в конце запускает единственную проверку для самого глубокого подкаталога. Но вам нужно проверить каждый подкаталог по отдельности, чтобы увидеть, является ли он глубже текущего максимума, и в конце сообщить о самом глубоком из них.
  • Двойная кавычка вашей переменной ссылки (как я сделал с "$dir/$i" выше) Ссылки на переменные без кавычек могут быть разбиты на слова и расширены подстановочными знаками, что является источником большого горя. Похоже, вам нужно оставить $sub без кавычек, потому что вам нужно , чтобы разделить его на слова, но это сделает сценарий неспособным справиться с именами каталогов с пробелами. См. BashFAQ # 20: «Как я могу найти и безопасно обрабатывать имена файлов, содержащие переводы строк, пробелы или оба?»
  • Тест if [ -n "$sub" ] ; then не имеет значения. Если $sub пусто, цикл никогда не запустится.
  • В сценарии оболочки относительные пути (например, ./depthScript) относятся к любому рабочему каталогу родительского процесса, , а не к местоположению сценария. Если кто-то запускает ваш скрипт из другого каталога, ./depthScript не будет работать. Вместо этого используйте "$BASH_SOURCE". См. BashFAQ # 28: «Как определить местоположение моего скрипта? Я хочу прочитать некоторые файлы конфигурации из того же места».
  • При попытке устранения неполадок в скрипте может помочь поставить set -x перед проблемным разделом. Это заставляет оболочку печатать каждую команду во время ее выполнения, чтобы вы могли видеть, что происходит.
  • Запустите ваши скрипты через shellcheck.net - это укажет на множество распространенных ошибок.
0 голосов
/ 25 апреля 2018

Вы можете использовать bash functions для создания рекурсивных вызовов функций.

В идеальном случае ваша функция будет отображать 0 в базовом случае, когда она вызывается в каталоге без подкаталогов, иecho 1+$(getDepth $subdir) в случае, когда существует некоторый подкаталог $subdir.См. этот вопрос о рекурсивных функциях в bash для фреймворка.

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