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

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

 Новая версия 

 #!/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))" 

 Пример запуска скрипта 

 

 Пример генерируемой структуры 

 

                                       Старая версия                              

 

 #!/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 созданий 

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