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

时间:2011-04-10 22:41:45

标签: batch-file windows-vista

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

第一组数字表示它来自哪个“包”,第二组数字仅用于区分它们。因此,在此示例中,我们在包001中有一个文件,在包002中有三个文件。

我正在编写一个windows vista batch命令来获取所有文件并将它们移动到自己的目录中,其中每个目录代表一个不同的包。所以我想将包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输入了不同的文件,所有这些都是最后一个包的名字。我猜错了我的设置方式。

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

3 个答案:

答案 0 :(得分:54)

您的问题是当批处理器在执行之前读取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!
)

有关详细信息,请参阅here

答案 1 :(得分: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

为什么这样?一个原因是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语句之外,并且忽略最后的)

答案 2 :(得分:4)

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

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

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