Скрипт для генерации произвольной структуры файлов и папок
Скрипт генерации
Новая версия
#!/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))"Пример генерируемой структуры
Старая версия
#!/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 созданий
Пример вывода с такими настройками:


