windows批处理文件:在for循环中设置变量

MxL*_*evs 25 batch-file windows-vista

我有许多具有相同命名方案的文件.作为示例,四个文件称为"num_001_001.txt","num_002_001.txt","num_002_002.txt","num_002_003.txt"

第一组数字表示它来自哪个"包",第二组数字仅用于区分它们.所以在这个例子中,我们在包001中有一个文件,在包002中有三个文件.

我正在编写一个windows vista批处理命令来获取所有文件并将它们移动到自己的目录中,其中每个目录代表一个不同的包.所以我想将包001的所有文件移动到目录"001"中,并将002的所有文件移动到目录"002"中

我已成功编写了一个脚本,它将迭代所有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输入了不同的文件,所有这些都是最后一个包的名字.我猜错了我的设置方式.

我有不同的解决方法来完成工作,但我很困惑为什么这么简单的概念不起作用.

con*_*tor 54

您的问题是,当批处理器在执行之前读取for命令时,变量会被替换.

试试这个:

SET temp=Hello, world!
CALL yourbatchfile.bat
Run Code Online (Sandbox Code Playgroud)

你会看到Hello打印5次.

解决方案是延迟扩张; 你需要先启用它,然后使用!temp!而不是%temp%:

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /R %%X IN (*.txt) DO (
  set temp=%%~nX
  echo directory !temp:~0,7!
)
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参见此处


bk1*_*k1e 14

另一种解决方案是将for循环体移动到子程序中call.

@echo off
FOR /R %%X IN (*.txt) DO call :body %%X
goto :eof

:body
set temp=%~n1
echo directory %temp:~0,7%
goto :eof
Run Code Online (Sandbox Code Playgroud)

为什么这样?一个原因是Windows命令处理器对括号贪婪,结果可能令人惊讶.我通常在解除引用包含的变量时遇到这种情况C:\Program Files (x86).

如果Windows命令处理器不那么贪婪,则以下代码将打印One (1) Two (2)或根本不打印:

@echo off
if "%1" == "yes" (
   echo 1 (One)
   echo 2 (Two)
)
Run Code Online (Sandbox Code Playgroud)

然而,这不是它的作用.它打印1 (One 2 (Two),丢失),或打印2 (Two).命令处理器将)after 解释Oneif语句正文的结尾,将第二个echo视为在if语句之外,并忽略final ).


bk1*_*k1e 6

我不确定这是否有正式记录,但您可以使用以下call语句模拟延迟扩展:

@echo off
FOR /R %%X IN (*.txt) DO (
  set temp=%%~nX
  call echo directory %%temp:~0,7%%
)
Run Code Online (Sandbox Code Playgroud)

将百分号加倍会将变量替换推迟到第二次评估。然而,延迟扩张要简单得多。