Подтвердить что ты не робот

Пакетные файлы окон: настройка переменной для цикла

У меня есть несколько файлов с одинаковой схемой именования. В качестве примера четыре файла называются "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, и все это было последним именем пакета. Я угадываю что-то не так, как я настраиваю вещи.

У меня разные способы обхода, чтобы выполнить эту работу, но я сбив с толку, почему такая простая концепция не сработает.

4b9b3361

Ответ 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%%
)

Удвоение процентных знаков отменяет замену переменных на вторую оценку. Однако отсроченное расширение намного проще.