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

发布于 2024-10-31 14:41:09 字数 985 浏览 1 评论 0原文

我有许多具有相同命名方案的文件。作为示例,四个文件分别称为“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 放入不同的文件,所有这些都是最后一个包的名称。我猜我的设置方式有问题。

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

I have a number of files with the same naming scheme. As a sample, four files are called "num_001_001.txt", "num_002_001.txt", "num_002_002.txt", "num_002_003.txt"

The first set of numbers represents which "package" it's from, and the second set of numbers is simply used to distinguish them from one another. So in this example we have one file in package 001, and three files in package 002.

I am writing a windows vista batch command to take all of the files and move them into their own directories, where each directory represents a different package. So I want to move all the files for package 001 into directory "001" and all for 002 into directory "002"

I have successfully written a script that will iterate over all of the txt files and echo them. I have also written a scrip that will move one file into another location, as well as creating the directory if it doesn't exist.

Now I figure that I will need to use substrings, so I used the %var:~start,end% syntax to get them. As a test, I wrote this to verify that I can actually extract the substring and create a directory conditionally

@echo off
set temp=num_001_001.txt
NOT IF exist %temp:~0,7%\
  mkdir %temp:~0,7%

And it works. Great.
So then I added the for loop to it.

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

But this is my output:

directory num_002
directory num_002
directory num_002
directory num_002

What's wrong? Does vista not support re-assigning variables in each iteration?
The four files are in my directory, and one of them should create num_001. I put in different files with 003 004 005 and all of it was the last package's name. I'm guessing something's wrong with how I'm setting things.

I have different workarounds to get the job done but I'm baffled why such a simple concept wouldn't work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

哥,最终变帅啦 2024-11-07 14:41:09

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

请参阅 此处 了解更多详细信息。

Your problem is that the variable get replaced when the batch processor reads the for command, before it is executed.

Try this:

SET temp=Hello, world!
CALL yourbatchfile.bat

And you'll see Hello printed 5 times.

The solution is delayed expansion; you need to first enable it, and then use !temp! instead of %temp%:

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

See here for more details.

南汐寒笙箫 2024-11-07 14:41:09

另一种解决方案是将 for 循环体移至子例程并调用它。

@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 它位于 if 语句之外,并忽略最后的 )

Another solution is to move the body of the for loop to a subroutine and 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

Why do this? One reason is that the Windows command processor is greedy about parentheses, and the results may be surprising. I usually run into this when dereferencing variables that contain C:\Program Files (x86).

If the Windows command processor was less greedy, the following code would either print One (1) Two (2) or nothing at all:

@echo off
if "%1" == "yes" (
   echo 1 (One)
   echo 2 (Two)
)

However, that's not what it does. Either it prints 1 (One 2 (Two), which missing a ), or it prints 2 (Two). The command processor interprets the ) after One as the end of the if statement's body, treats the second echo as if it's outside the if statement, and ignores the final ).

奢望 2024-11-07 14:41:09

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

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

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

I'm not sure whether this is officially documented, but you can simulate delayed expansion using the call statement:

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

Doubling the percent signs defers the variable substitution to the second evaluation. However, delayed expansion is much more straightforward.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文