У меня есть файл data.txt, который я анализирую в своем скрипте .cmd, я просматриваю его от первой строки до последней. Я хочу начать с последней строки и вместо этого перейти к первой.
FOR /F "EOL=; TOKENS=1 DELIMS = " %%r IN (datafile) DO
(CALL :DeleteFolder %%r
)
Как я смогу изменить порядок чтения?
Я пытался найти синтаксис для «FOR /....», но, похоже, невозможно найти хорошую документацию для .cmd или пакетных файлов (вопрос в вопросе: файл .cmd совпадает с пакетным файлом и .bat, синтаксис кажется таким же, и всякий раз, когда я ищу файл .cmd, мне отображается справка по пакетному файлу).
Это образец файла данных, с которым я сейчас работаю в целях тестирования. Реальный файл данных будет состоять из пары сотен строк и часто меняться, он должен составлять около 300 строк. По сути, это определение структуры папок и подпапок.
; This is a comment line
DEV1
DEV2
DEV3
DEV4
DEV5
DEV6
DEV7
DEV8
DEV9
DEV10
; This is a comment line
Пожалуйста, внесите в свой вопрос репрезентативный образец вашего файла данных. Поможет ли обратная сортировка?
Вы не можете «обратить порядок чтения»! Файл все равно будет прочитан с самого начала. У вас будет возможность прочитать все строки с начала файла и сохранить каждую строку в обратном порядке. Как вы можете себе представить, во всех файлах, кроме небольших, для этого потребуется либо большой буфер памяти, либо временный файл. Также в вашем примере EOL=; TOKENS=1
не требуется, а CALL :DeleteFolder %%r
должно быть CALL :DeleteFolder "%%~r"
.
Файл, который я читаю, постоянно обновляется, поэтому я не могу изменить его содержимое. В настоящее время я создаю это решение с использованием меньшего образца фактического файла данных, поскольку он довольно большой.
Короткий ответ: вы не можете. Файл всегда читается в естественном порядке. Обычный способ решения этой проблемы — сохранить все строки файла в переменных и затем обработать переменные в обратном порядке. Проблемы с этим методом возникают, когда файл большой, поскольку пространство для переменных ограничено, и процесс становится медленнее по мере увеличения размера файла...
Я разработал интересный метод обработки строк файла в обратном порядке, не использующий переменные. Вместо этого он сохраняет каждую ожидающую строку в заменяемом параметре FOR и обрабатывает несколько строк посредством вложенных рекурсивных вызовов подпрограммы, содержащей команду FOR. Таким образом, максимальное количество строк, которые можно обработать с помощью этого метода, — это максимальный уровень вызовов подпрограмм, которые поддерживает cmd.exe, который, я думаю, составляет несколько сотен.
В любом случае, этот метод интересен! ;)
@echo off
setlocal EnableDelayedExpansion
set "last=1"
:rolling
set "first=0"
for /F "delims = " %%a in (data.txt) do if defined last (
set /A first+=1
if !first! equ %last% (
set /A last+=1
call :rolling
echo(%%a
set "last = "
)
)
exit /B
Другое возможное решение — полностью перевернуть строки файла, а затем обработать его как обычно. Этого можно добиться с помощью этого кода:
@echo off
setlocal EnableDelayedExpansion
rem/> output.txt
for /F "delims = " %%a in (test.txt) do (
(
echo(%%a
type output.txt
) > temp.txt
move /Y temp.txt output.txt > NUL
)
Спасибо за помощь, сейчас пытаюсь реализовать. У меня возникли проблемы с пониманием того, где я буду вызывать функцию DeleteFolder. Я новичок в пакетном написании сценариев, почему вы используете ! чтобы заключить первую переменную, а не %%, как обычно заключаются переменные, и является ли последняя проверка «делать, если определено» истинной/ложной?
@NimaPishva второй пример должен быть довольно очевиден. Файл output.txt представляет собой перевернутый файл. Итак, теперь вы просто используете это с существующей командой for. FOR /F "EOL=; TOKENS=1 DELIMS = " %%r IN (output.txt) DO (CALL :DeleteFolder %%r)
спасибо, мне удалось заставить его работать.
Что ж, этот метод должен работать быстрее, чем другой, который выполняет команду findstr
в каждой строке файла...
Предел рекурсии составляет 339. Это пугающе близко к «паре сотен… около 300». Подготовьтесь к переполнению стека (каламбур), если вы используете этот (рекурсивный) метод. Хотя интересное решение. Второе предложение выполняет как минимум две операции записи на строку (должно быть «медленно» на вращающихся дисках).
for /L
для обработки их в обратном порядке. @echo off
setlocal
set "file=data.txt"
REM create a file with line numbers (while removing comments):
findstr /bv ";" "%file%" | findstr /n "^" > "%file%.tmp"
REM find number of lines:
for /f %%i in ('type "%file%.tmp"^|find /c /v ""') do set lines=%%i
REM process them in reverse order:
for /l %%i in (%lines%,-1,1) do (
for /f "tokens=1,* delims=:" %%x in ('findstr /b "%%i:" "%file%.tmp"') do (
echo processing line number %%x: %%y
)
)
del "%file%.tmp"
Для каждой строки существует операция чтения (плюс одна для создания временного файла и одна для подсчета строк), но только одна операция записи (создание временного файла). Никакие данные не хранятся в памяти (кроме обрабатываемой строки), поэтому нет опасности превышения места для переменных или предела рекурсии.
Пустые строки сохраняются (в примере данных их нет), но при необходимости их можно отфильтровать с помощью другого findstr
.
Спасибо, это сработало, мой файл данных перевернут! в консоли. Однако когда я вставляю вызов: DeleteFolder, он не работает. Например, куда пойдет мой вызов функции?
У меня получилось, спасибо!
is a .cmd file the same as a batch file and a .bat file
- есть небольшие отличия, но по сути да.