Пакетные файлы окон: настройка переменной для цикла
У меня есть несколько файлов с одинаковой схемой именования. В качестве примера четыре файла называются "num_001_001.txt", "num_002_001.txt", "num_002_002.txt", "num_002_003.txt"
Первый набор чисел представляет собой "пакет" из него, а второй набор чисел просто используется, чтобы отличать их друг от друга. Итак, в этом примере у нас есть один файл в пакете 001 и три файла в пакете 002.
Я пишу командную команду windows vista, чтобы взять все файлы и переместить их в свои собственные каталоги, где каждый каталог представляет собой другой пакет. Поэтому я хочу переместить все файлы для пакета 001 в каталог "001" и все для 002 в каталог "002"
Я успешно написал script, который будет перебирать все файлы txt и эхо их. Я также написал сценарий, который переместит один файл в другое место, а также создаст каталог, если он не существует.
Теперь я полагаю, что мне нужно будет использовать подстроки, поэтому я использовал синтаксис% var: ~ start, end%, чтобы получить их. В качестве теста я написал это, чтобы убедиться, что я действительно могу извлечь подстроку и создать каталог условно
@echo off
set temp=num_001_001.txt
NOT IF exist %temp:~0,7%\
mkdir %temp:~0,7%
И это работает. Отлично.
Итак, я добавил цикл for к нему.
@echo off
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
echo directory %temp:~0,7%
)
Но это мой вывод:
directory num_002
directory num_002
directory num_002
directory num_002
Что случилось? Не поддерживает ли Vista переназначение переменных на каждой итерации?
Эти четыре файла находятся в моем каталоге, и один из них должен создать num_001. Я поместил в разные файлы с 003 004 005, и все это было последним именем пакета. Я угадываю что-то не так, как я настраиваю вещи.
У меня разные способы обхода, чтобы выполнить эту работу, но я сбив с толку, почему такая простая концепция не сработает.
Ответы
Ответ 1
Ваша проблема в том, что переменная get заменяется, когда пакетный процессор считывает команду for перед ее выполнением.
Попробуйте следующее:
SET temp=Hello, world!
CALL yourbatchfile.bat
И вы увидите Hello напечатано 5 раз.
Решение задерживается расширением; вам нужно сначала включить его, а затем использовать !temp!
вместо %temp%
:
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
echo directory !temp:~0,7!
)
Подробнее см. здесь.
Ответ 2
Другим решением является перемещение тела цикла for
в подпрограмму и call
it.
@echo off
FOR /R %%X IN (*.txt) DO call :body %%X
goto :eof
:body
set temp=%~n1
echo directory %temp:~0,7%
goto :eof
Зачем? Одна из причин заключается в том, что командный процессор Windows жадничает по круглым скобкам, и результаты могут быть неожиданными. Я обычно сталкиваюсь с этим при разыменовании переменных, содержащих C:\Program Files (x86)
.
Если командный процессор Windows был менее жадным, следующий код либо напечатал бы One (1)
Two (2)
, либо вообще ничего:
@echo off
if "%1" == "yes" (
echo 1 (One)
echo 2 (Two)
)
Однако это не то, что он делает. Либо он печатает 1 (One
2 (Two)
, который пропускает )
, либо печатает 2 (Two)
. Командный процессор интерпретирует )
после One
как конец тела оператора if
, обрабатывает второй echo
, как если бы он находился вне оператора if
, и игнорировал окончательный )
.
Ответ 3
Я не уверен, что это официально задокументировано, но вы можете имитировать замедленное расширение с помощью инструкции call
:
@echo off
FOR /R %%X IN (*.txt) DO (
set temp=%%~nX
call echo directory %%temp:~0,7%%
)
Удвоение процентных знаков отменяет замену переменных на вторую оценку. Однако отсроченное расширение намного проще.