Skip to main content

Скрипт для генерации произвольной структуры файлов и папок

Скрипт генерации

#!/usr/bin/env bash
set -euo pipefail

# === Настройки (можно переопределять через ENV) ===
ROOT_DIR="${ROOT_DIR:-./upload_test_tree}"  # куда генерить
TOTAL_ITEMS="${TOTAL_ITEMS:-40000}"         # всего объектов (файлы+папки)
FILES_COUNT="${FILES_COUNT:-10000}"         # сколько файлов
MAX_DEPTH="${MAX_DEPTH:-8}"                 # максимальная глубина (root=0)
PRINT_EVERY="${PRINT_EVERY:-1000}"          # прогресс раз в N созданий

# === Валидация ===
if (( FILES_COUNT > TOTAL_ITEMS )); then
  echo "FILES_COUNT ($FILES_COUNT) не может быть больше TOTAL_ITEMS ($TOTAL_ITEMS)" >&2
  exit 1
fi

DIRS_COUNT=$((TOTAL_ITEMS - FILES_COUNT))   # директорий (включая root? нет)
# Мы отдельно создаём root, поэтому целевая сумма директорий = DIRS_COUNT + 1

rm -rf -- "$ROOT_DIR"
mkdir -p -- "$ROOT_DIR"

# Списки директорий и их глубин
dirs=("$ROOT_DIR")
depths=(0)

created_dirs=1      # root уже создан
created_files=0
created_total=0     # будем считать созданные "объекты" сверх root

mkname() {
  local prefix="$1"
  # Быстро и "достаточно уникально" без urandom/openssl:
  # счётчик + BASHPID + RANDOM
  echo "${prefix}_${BASHPID}_${created_total}_${RANDOM}${RANDOM}"
}

pick_parent_for_file() {
  echo $(( RANDOM % ${#dirs[@]} ))
}

pick_parent_for_dir() {
  local tries=8 idx
  while (( tries-- > 0 )); do
    idx=$(( RANDOM % ${#dirs[@]} ))
    if (( depths[idx] < MAX_DEPTH )); then
      echo "$idx"
      return
    fi
  done
  for idx in "${!dirs[@]}"; do
    if (( depths[idx] < MAX_DEPTH )); then
      echo "$idx"
      return
    fi
  done
  # если всё на MAX_DEPTH — просто вернём любой
  echo $(( RANDOM % ${#dirs[@]} ))
}

echo "ROOT_DIR=$ROOT_DIR"
echo "TOTAL_ITEMS=$TOTAL_ITEMS (dirs=$DIRS_COUNT, files=$FILES_COUNT), MAX_DEPTH=$MAX_DEPTH"
echo

target_dirs=$((DIRS_COUNT + 1))   # + root
target_files=$FILES_COUNT
target_total=$TOTAL_ITEMS

while (( (created_dirs + created_files) < target_total )); do
  remaining_dirs=$(( target_dirs - created_dirs ))
  remaining_files=$(( target_files - created_files ))

  make_dir=0
  if (( remaining_dirs > 0 && remaining_files > 0 )); then
    roll=$(( RANDOM % (remaining_dirs + remaining_files) ))
    if (( roll < remaining_dirs )); then make_dir=1; fi
  elif (( remaining_dirs > 0 )); then
    make_dir=1
  else
    make_dir=0
  fi

  if (( make_dir == 1 )); then
    pidx="$(pick_parent_for_dir)"
    parent="${dirs[pidx]}"
    dname="$(mkname d)"
    newdir="$parent/$dname"
    mkdir -p -- "$newdir"
    dirs+=("$newdir")
    depths+=($(( depths[pidx] + 1 )))
    ((++created_dirs))
  else
    pidx="$(pick_parent_for_file)"
    parent="${dirs[pidx]}"
    fname="$(mkname f)"
    : > "$parent/$fname.bin"
    ((++created_files))
  fi

  ((++created_total))

  if (( created_total % PRINT_EVERY == 0 )); then
    echo "Created: total=$((created_dirs + created_files)) dirs=$created_dirs files=$created_files (dir_pool=${#dirs[@]})"
  fi
done

echo
echo "DONE."
echo "Path: $ROOT_DIR"
echo "Dirs created (incl root): $created_dirs"
echo "Files created: $created_files"
echo "Total created: $((created_dirs + created_files))"

Пример использования скрипта 

Настройки генерации:

ROOT_DIR="${ROOT_DIR:-./upload_test_tree}"  # куда генерить
TOTAL_ITEMS="${TOTAL_ITEMS:-40000}"         # всего объектов (файлы+папки)
FILES_COUNT="${FILES_COUNT:-10000}"         # сколько файлов
MAX_DEPTH="${MAX_DEPTH:-8}"                 # максимальная глубина (root=0)
PRINT_EVERY="${PRINT_EVERY:-40000}"         # прогресс раз в N созданий

Пример вывода с такими настройками:

image.png