Поиск по сайту:

Как обойти дерево каталогов в Linux


Каталоги в Linux позволяют группировать файлы в отдельные коллекции. Недостатком является утомительное перемещение из каталога в каталог для выполнения повторяющейся задачи. Вот как это автоматизировать.

Все о каталогах

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

Понимание концепции дерева каталогов и того, как перемещаться между ними, — это одна из многих небольших вех, которые вы проходите, знакомясь с ландшафтом Linux. Использование cd с путем приведет вас к этому каталогу. Ярлыки, такие как cd ~ или cd, сами по себе возвращают вас в ваш домашний каталог, а cd .. перемещает вас на один уровень вверх в каталоге. дерево. Простой.

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

Некоторые команды, такие как ls, имеют параметры командной строки, которые заставляют их работать рекурсивно, то есть они начинаются в одном каталоге и методично работают со всем деревом каталогов ниже этого каталога. . Для ls это параметр -R (рекурсивный).

Если вам нужно использовать команду, которая не поддерживает рекурсию, вы должны сами обеспечить рекурсивную функциональность. Вот как это сделать.

Команда дерева

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

Вам нужно будет установить tree .

В Ubuntu вам нужно ввести:

sudo apt install tree

В Fedora используйте:

sudo dnf install tree

На Manjaro команда такая:

sudo pacman -Sy tree

Использование tree без параметров рисует дерево под текущим каталогом.

tree

Вы можете передать путь к tree в командной строке.

tree work

Параметр -d (каталоги) исключает файлы и показывает только каталоги.

tree -d work

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

Не анализируйте вывод из ls в обход каталогов

Ваша первая мысль может быть такой: если ls может рекурсивно перемещаться по дереву каталогов, почему бы не использовать ls именно для этого и направить вывод в некоторые другие команды, которые анализируют каталоги и выполнить какие-то действия?

Анализ вывода ls считается плохой практикой. Из-за возможности Linux создавать имена файлов и каталогов, содержащие всевозможные странные символы, становится очень сложно создать универсальный, универсальный синтаксический анализатор.

Возможно, вы никогда не создадите сознательно такое нелепое имя каталога, но ошибка в сценарии или приложении может.

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

Использование команды поиска

Команда find имеет встроенные рекурсивные возможности, а также может запускать команды для нас. Это позволяет нам создавать мощные однострочники. Если это то, что вы, вероятно, захотите использовать в будущем, вы можете превратить свою однострочную строку в псевдоним или функцию оболочки.

Эта команда рекурсивно просматривает дерево каталогов в поисках каталогов. Каждый раз, когда он находит каталог, он выводит имя каталога и повторяет поиск внутри этого каталога. Завершив поиск в одном каталоге, он выходит из этого каталога и возобновляет поиск в своем родительском каталоге.

find work -type d -execdir echo "In:" {} \;

По порядку, в котором перечислены каталоги, можно увидеть, как продвигается поиск по дереву. Сравнив вывод команды tree с выводом однострочной команды find, вы увидите, как find выполняет поиск в каждом каталоге и подкаталоге. по очереди, пока не попадет в каталог без подкаталогов. Затем он возвращается на уровень вверх и возобновляет поиск на этом уровне.

Вот как составляется команда.

  • найти: команда найти.
  • work: каталог, в котором нужно начать поиск. Это может быть путь.
  • -тип d: мы ищем каталоги.
  • -execdir: мы собираемся выполнить команду в каждом найденном каталоге.
  • echo «In:» {}: это команда. Мы просто повторяем имя каталога в окне терминала. «{}» содержит имя текущего каталога.
  • \;: точка с запятой, используемая для завершения команды. Нам нужно экранировать его с помощью обратной косой черты, чтобы Bash не интерпретировал его напрямую.

С небольшим изменением мы можем заставить команду find возвращать файлы, соответствующие ключу поиска. Нам нужно включить опцию -name и подсказку для поиска. В этом примере мы ищем текстовые файлы, соответствующие «*.txt», и выводим их имя в окно терминала.

find work -name "*.txt" -type f -execdir echo "Found:" {} \;

Ищете ли вы файлы или каталоги, зависит от того, чего вы хотите достичь. Чтобы запустить команду внутри каждого каталога, используйте -type d . Чтобы запустить команду для каждого подходящего файла, используйте -type f.

Эта команда подсчитывает строки во всех текстовых файлах в начальном каталоге и подкаталогах.

find work -name "*.txt" -type f -execdir wc -l {} \;

Обход дерева каталогов с помощью скрипта

Если вам нужно просмотреть каталоги внутри скрипта, вы можете использовать команду find внутри вашего скрипта. Если вам нужно — или вы просто хотите — выполнить рекурсивный поиск самостоятельно, вы тоже можете это сделать.

#!/bin/bash

shopt -s dotglob nullglob

function recursive {

  local current_dir dir_or_file

  for current_dir in $1; do

    echo "Directory command for:" $current_dir

    for dir_or_file in "$current_dir"/*; do

      if [[ -d $dir_or_file ]]; then
        recursive "$dir_or_file"
      else
        wc $dir_or_file
      fi
    done
  done
}

recursive "$1"

Скопируйте текст в редактор и сохраните его как «recurse.sh», затем используйте команду chmod, чтобы сделать его исполняемым.

chmod +x recurse.sh

Сценарий устанавливает два параметра оболочки: dotglob и nullglob.

Параметр dotglob означает, что имена файлов и каталогов, начинающиеся с точки «.», будут возвращаться при раскрытии условий поиска с подстановочными знаками. Фактически это означает, что мы включаем скрытые файлы и каталоги в наши результаты поиска.

Параметр nullglob означает, что шаблоны поиска, которые не находят никаких результатов, обрабатываются как пустая или нулевая строка. По умолчанию они не относятся к самому поисковому запросу. Другими словами, если мы ищем все в каталоге, используя подстановочный знак звездочки «*», но результатов нет, мы получим нулевую строку вместо строки, содержащей звездочку. Это предотвращает непреднамеренную попытку сценария открыть каталог с именем «*» или трактовать «*» как имя файла.

Затем он определяет функцию с именем recursive. Здесь происходят интересные вещи.

Объявляются две переменные, называемые current_dir и dir_or_file. Это локальные переменные, и на них можно ссылаться только внутри функции.

Внутри функции также используется переменная с именем $1. Это первый (и единственный) параметр, передаваемый функции при ее вызове.

Сценарий использует два цикла for, один из которых вложен в другой. Первый (внешний) цикл for используется для двух целей.

Один из них — запустить любую команду, которую вы хотите выполнить в каждом каталоге. Все, что мы здесь делаем, — это вывод имени каталога в окно терминала. Конечно, вы можете использовать любую команду или последовательность команд или вызвать другую функцию сценария.

Во-вторых, внешний цикл for проверяет все объекты файловой системы, которые он может найти, будь то файлы или каталоги. Это цель внутреннего цикла for. В свою очередь, имя каждого файла или каталога передается в переменную dir_or_file.

Затем переменная dir_or_file проверяется в операторе if, чтобы определить, является ли она каталогом.

  • Если это так, функция вызывает себя и передает имя каталога в качестве параметра.
  • Если переменная dir_or_file не является каталогом, то это должен быть файл. Любые команды, которые вы хотите применить к файлу, можно вызвать из предложения else оператора if. Вы также можете вызвать другую функцию в том же скрипте.

Последняя строка скрипта вызывает функцию recursive и передает в первой командной строке параметр $1 в качестве начального каталога для поиска. что запускает весь процесс.

Запустим скрипт.

./recurse.sh work

Каталоги просматриваются, и точка в сценарии, где команда будет выполняться в каждом каталоге, указывается строками «Команда каталога для:». Для найденных файлов выполняется команда wc для подсчета строк, слов и символов.

Первый обрабатываемый каталог — это «рабочий», за которым следуют все вложенные ветки каталогов дерева.

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

Давайте переместим строку «Directory command for:» после done внутреннего цикла for.

#!/bin/bash

shopt -s dotglob nullglob

function recursive {

  local current_dir dir_or_file

  for current_dir in $1; do

    for dir_or_file in "$current_dir"/*; do

      if [[ -d $dir_or_file ]]; then
        recursive "$dir_or_file"
      else
        wc $dir_or_file
      fi

    done

    echo "Directory command for:" $current_dir

  done
}

recursive "$1"

Теперь запустим скрипт еще раз.

./recurse.sh work

На этот раз к каталогам сначала применяются команды с самых глубоких уровней, работая с ветвями дерева. Каталог, переданный скрипту в качестве параметра, обрабатывается последним.

Если важно, чтобы в первую очередь обрабатывались более глубокие каталоги, вот как вы можете это сделать.

Рекурсия странная

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

Может потребоваться некоторое усилие, прежде чем вы поймете его преимущества, но когда вы это сделаете, вы увидите, что это программно элегантный способ решения сложных проблем.