5/jekyll_site/ru/2023/08/03/directory-tree.md
2024-12-29 10:39:46 +03:00

4 KiB
Raw Blame History

title description sections tags canonical_url url_translated title_translated date
Дерево каталогов со ссылками Напишем скрипт Bash для построения дерева каталогов для репозитория в файле Markdown. Будем использовать только средства Bash и базовое ПО Linux без...
Рекурсия
Обработка файлов
Вёб-навигация
linux
bash
markdown
html
структура
каталоги
файлы
ссылки
сортировка
/ru/2023/08/03/directory-tree.html /en/2023/08/04/directory-tree.html Directory tree with links 2023.08.03

Напишем скрипт Bash для построения дерева каталогов для репозитория в файле Markdown. Будем использовать только средства Bash и базовое ПО Linux — ls, sed, tr и echo — без дополнительных программ. Полученный файл [DIRECTORY_TREE.md]({{ site.homepage_url }} "{{ site.homepage_name }}") будем использовать в вёб-интерфейсе для навигации по объектам репозитория.

Создаём рекурсивную функцию и с её помощью обходим все файлы и каталоги репозитория, за исключением списка из .gitignore — строим структуру каталогов в форме дерева. Выводим элементы в виде ссылок <a>, сворачиваем папки с одним вложенным элементом в одну строку, помещаем собранное дерево в контейнер <pre> и добавляем заголовок — в результате получаем краткий и лаконичный файл Markdown со ссылками.

#!/bin/bash
# отсортированный список файлов и каталогов
function list_directory_contents {
  # сначала заглавные буквы, потом строчные, сначала каталоги, потом файлы
  eval "LC_COLLATE=C ls -A --group-directories-first $exclusions $1"
}
# дерево каталогов со ссылками
function directory_tree {
  # аргументы
  local path="$1"
  local head="$2"
  local tail="$3"
  # префикс для текущего элемента
  [ "one" == "$4" ] && printf '%s' "/" || printf '\n%s' "$head"
  # текущий элемент дерева
  printf '%s' "<a href='${path#*/}'>${path##*/}</a>"
  # рекурсивные вызовы для подкаталогов
  if [ -d "$path" ]; then
    local list # массив файлов и каталогов
    readarray -t list < <(list_directory_contents "$path")
    local size=${#list[@]} # длина массива
    local i # счётчик
    for ((i = 0; i < size; i++)); do
      if [ -z "${list[$i]}" ]; then
        continue # пропустить пустой каталог
      elif ((size == 1)); then
        directory_tree "$path/${list[$i]}" "$tail" "$tail" "one"
      elif ((i < size - 1)); then
        directory_tree "$path/${list[$i]}" "$tail├─ " "$tail│  "
      else
        directory_tree "$path/${list[$i]}" "$tail└─ " "$tail   "
      fi
    done
  fi
}
# строка исключений для "ls" из списка неотслеживаемых файлов ".gitignore"
exclusions="-I'.git' $(sed -E "s|^(.*)$|-I'\1'|" .gitignore | tr '\n' ' ')"
# помещаем дерево в контейнер, добавляем заголовок и выводим в файл
printf '%s\n' "## Дерево каталогов" "" "<pre>" \
  "$(directory_tree . | grep '\S')" "</pre>" >DIRECTORY_TREE.md

Запускаем скрипт в корне репозитория и сохраняем полученный файл.