Я предлагаю следующий пакетный файл для этой задачи:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
:GetFolderCount
set "FolderCount="
set /P "FolderCount=How many subdirectories would you like to add in each folder? "
rem Has the user entered anything at all?
if not defined FolderCount goto GetFolderCount
rem Has the user entered a string not consisting only of digits?
for /F delims^=0123456789^ eol^= %%I in ("!FolderCount!") do goto GetFolderCount
rem Has the user entered a positive integer too large for Windows command
rem processor or being interpreted octal by cmd.exe because of leading zeros?
set /A TempCount=FolderCount
if not %TempCount% == %FolderCount% goto GetFolderCount
set "TempCount="
if not %FolderCount% == 0 (
for /L %%I in (1,1,%FolderCount%) do (
set "FolderName="
set /P "FolderName=What is the name of subdirectory %%I? "
if defined FolderName for /F "eol=| delims=" %%J in (list.txt) do md "%%~J\!FolderName!"
)
)
endlocal
Пакетный файл не верит, что пользователь вводит всегда правильное целое положительное число.Поэтому пакетный файл сначала удаляет переменную среды FolderCount
.
. Затем он запрашивает у пользователя пакетного файла количество подкаталогов.FolderCount
по-прежнему не определено, если пользователь просто нажимает RETURN или ENTER , что приводит к повторному запросу пользователя.Было бы также возможно определить FolderCount
со значением наподобие 1
, прежде чем предлагать пользователю установить значение по умолчанию, которое пользователь может использовать, просто нажав клавишу RETURN или ENTER .
Пользователь может свободно преднамеренно или по ошибке вводить любую строку, а не просто положительное целое число, как ожидается в пакетном файле.Поэтому проверяется следующее, что введенная строка действительно состоит только из цифр.
FOR при использовании опции /F
игнорирует пустые строки (больше невозможно) и строки, начинающиеся с ;
.Введенная строка, начинающаяся с точки с запятой, должна интерпретироваться как неправильный ввод, что является причиной переопределения значения по умолчанию eol=;
до просто eol=
, чтобы определить отсутствие символа конца строки и, таким образом, не игнорировать строку независимо от того, что является первым символом.
FOR разбивает строку на подстроки (токены), используя по умолчанию обычный пробел и символ горизонтальной табуляции в качестве разделителей для подстрок, и назначает только первую подстроку указанной переменной цикла I
.Это поведение разделения строк модифицируется указанием delims=0123456789
всех цифр в качестве разделителей.Цикл FOR не выполняет команду GOTO , если введенная пользователем строка состоит только из цифр, так как в этом случае нельзя присвоить переменной цикла I
.Но команда GOTO выполняется FOR , если во введенной пользователем строке есть какой-либо другой символ, как в этом случае что-то назначено переменной цикла.
АльтернативныйДля определения списка разделителей используется метод не двойных кавычек, а также символ конца строки, который требует, чтобы два знака равенства и символ пробела между двумя опциями экранировались с помощью символа вставки ^
, так что вся строка опцийинтерпретируется как строка одного аргумента, как требуется для синтаксиса FOR .
После прохождения этой проверки введенная пользователем строка определенно состоит только из цифр.
Но она может иметь начальные нули, что приводит кпри интерпретации восьмеричного числа или число слишком большое, как 439871023842
.По этой причине введенная пользователем строка присваивается другой переменной среды с использованием арифметического выражения, которое приводит к преобразованию введенной пользователем строки в 32-разрядное целое число со знаком с диапазоном значений от 0
до 2147483647
, в этом случае из-за -
в начале больше невозможно.Полученное целое число затем преобразуется обратно в строку, которая присваивается переменной окружения TempCount
.Таким образом, если строка, присвоенная TempCount
, не равна строке, присвоенной FolderCount
, введенное пользователем значение не соответствует требованию быть положительным 32-разрядным десятичным целочисленным значением.
Что еще возможноявляется то, что пользователь ввел 0
для количества подкаталогов, в этом случае следующий блок вообще не выполняется, поскольку ничего не делать в соответствии с вводом пользователя.
Переменная окружения FolderName
всегда удаляется перед пользователемв цикле запрашивается имя папки.Таким образом, пользователь всегда должен вводить имя папки, или ничего не делается.Пользователь может использовать клавишу UP один или несколько раз, если следует еще раз использовать предыдущее введенное имя для подкаталога.
Подкаталоги создаются, как и ожидалось, при вводе пользователем непустой строкибыть действительным для имени папки в каждом подкаталоге, как определено в файле list.txt
в текущем каталоге.
Команда FOR с параметром /F
для чтения строк из файла list.txt
модифицируется параметрами eol=|
и delims=
, на этот раз указанными в строке аргумента с двойными кавычками, сне игнорировать строки, начинающиеся с точки с запятой и не разбивая каждую строку на подстроки из-за указания пустого списка разделителей.Вертикальная черта используется в качестве замены для ;
, поскольку имя папки не может содержать вертикальную черту, а точка с запятой в начале имени папки возможна.
Итак, вы определили delims=\n
для разделениястроки с обратной косой чертой или буквой n
, в то время как строка необязательного аргумента, заканчивающаяся delims=
, определяет пустой список разделителей, что приводит к полному отключению режима разбиения строк / строк и присвоению указанной переменной цикла J
всегда всей, не- пустая строка, считанная из файла списка, если она не начинается с вертикальной черты.
Примечание: Имена каталогов в list.txt
, содержащие один или несколько восклицательных знаков, обрабатываются некорректно из-за включенной задержкирасширение переменной среды.Но, похоже, здесь это не проблема.
Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды..
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
rem /?
set /?
setlocal /?