批处理文件中包含变量/文本文件中包含空格的文件名

3

我对编码一窍不通,所以请原谅我使用的术语可能不太准确!

我从网上选了一些批处理文件的代码(其中有些来自这个网站),并尝试重写其中的一部分以适应我的需求。

它创建一个新目录,然后查找另一个目录及其子目录中在 .txt 列表中的文件名,并将这些文件复制到最初创建的目录中。任何未在列表中找到的文件都会被写入另一个文本文件,以跟踪缺失的内容。

代码如下:

md 00FoundImages

set LIST=%cd%\imagelist.txt
set FILESPATH=%cd%\testimages
set DEST=%cd%\00FoundImages

for /f "delims=" %%x in (%LIST%) do (forfiles /p %FILESPATH% /s /m %%x* /c "cmd /c move /y @path %DEST%\@file" 2>>errors.txt)

在大多数情况下,这样做运行良好,但是当以下条件出现时会出现问题:

  1. 文本文件中的文件名包含空格
  2. 批处理文件所在目录的路径包含空格(或其他特殊字符)

我尝试过使用引号括起来,如下所示:

set FILELIST="%cd%\imagelist.txt"
set FILESPATH="%cd%\testimages"
set DESTPATH="%cd%\00FoundImages"

当目录名中有空格时,forfiles命令会失败。

我尝试在变量使用时用引号括起来,如下所示:

for /f "delims=" %%x in ("%LIST%") do (forfiles /p "%FILESPATH%" /s /m %%x* /c "cmd /c move /y @path "%DEST%\@file"" 2>>errors.txt)

当我从名为“testing-Copy”的目录运行批处理文件时,错误会被写入我的errors.txt文件中。
ERROR: Invalid argument/option - '-'.
Type "FORFILES /?" for usage.

这是正在发生的打印内容:
E:\ImageAutomationStuff\testing - Copy>md 00FoundImages
A subdirectory or file 00FoundImages already exists.

E:\ImageAutomationStuff\testing - Copy>set LIST=E:\ImageAutomationStuff\testing - Copy\imagelist.txt

E:\ImageAutomationStuff\testing - Copy>set FILESPATH=E:\ImageAutomationStuff\testing - Copy\testimages

E:\ImageAutomationStuff\testing - Copy>set DEST=E:\ImageAutomationStuff\testing - Copy\00FoundImages

E:\ImageAutomationStuff\testing - Copy>pause
Press any key to continue . . .

E:\ImageAutomationStuff\testing - Copy>for /F "delims=" %x in ("E:\ImageAutomationStuff\testing - Copy\imagelist.txt") do (forfiles /p "E:\ImageAutomationStuff\testing - Copy\testimages" /s /m %x* /c "cmd /c move /y @path "E:\ImageAutomationStuff\testing - Copy\00FoundImages\@file""  2>>errors.txt )

E:\ImageAutomationStuff\testing - Copy>(forfiles /p "E:\ImageAutomationStuff\testing - Copy\testimages" /s /m E:\ImageAutomationStuff\testing - Copy\imagelist.txt* /c "cmd /c move /y @path "E:\ImageAutomationStuff\testing - Copy\00FoundImages\@file""  2>>errors.txt )

E:\ImageAutomationStuff\testing - Copy>pause
Press any key to continue . . .

从我所做的研究中,我可以看到这类问题经常被问到 - 很抱歉增加了困扰,但由于我的知识有限,我恐怕无法自行解决此问题!


我已经尝试将变量用引号括起来,但这并不起作用。我已经以多种不同的方式完成了它,包括在“set”阶段和“for /f”阶段中将变量括起来。 - danmosa
你需要展示如何通过编辑你的问题将它们用引号括起来。 - user6017774
你加引号到指令本身时,是否移除了 set 命令中的引号。它应该在屏幕上打印出它正在做什么(这里没有人拥有与你相同的文件结构)。复制并粘贴那段代码。如果批处理中有 Echo Off,请用 (rem 表示注释)把它注释掉。 - user6017774
是的,我已经从“set”命令中删除了引号。我已将打印内容复制到我的原始帖子中。 - danmosa
引号应该包含变量名称和值,类似于 set "FILELIST=%cd%\imagelist.txt" - phuclv
显示剩余6条评论
3个回答

1
为了避免路径和文件名中的空格问题,请使用引号。但是在涉及到 forfiles 时需要小心,因为所有与路径和文件名相关的 @-变量都会被扩展为已经包含在 "" 中的值,所以很容易出现值被双引号引用的情况。
我建议你试一下这个方法:
md "%cd%\00FoundImages"

set "LIST=%cd%\imagelist.txt"
set "FILESPATH=%cd%\testimages"
set "DEST=%cd%\00FoundImages"

for /f "usebackq delims=" %%x in ("%LIST%") do (
    forfiles /p "%FILESPATH%" /s /m "%%x*" /c "cmd /c if @isdir==FALSE cd /d 0x22%DEST%0x22 & move /y @path @file" 2>>errors.txt
)

我做了什么:
  • 改进了set的语法,使整个赋值表达式都包含在""中;这避免了一些特殊字符的问题,但引号不是变量值的一部分;
  • 引用了%LIST%,所以我必须向for /f添加usebackq选项,因为否则它会将变量%LIST%的值视为字面字符串而不是文件;
  • /p后面的路径以及forfiles/m后面的模式都用括号括起来;这里非常重要的是,在/p后面的路径不能以\结尾,因为这会被forfiles解释为转义闭合引号"的字符;如果你无法确保%FILESPATH%符合这个条件,那么请写成/p "%FILESPATH%\."编辑:最后一句话是错误的!
  • @path变量扩展为已经带引号的字符串,所以一切都很好;
  • 棘手的部分是源代码中的目标文件%DEST%\@file,因为@file扩展为已经带引号的字符串,所以结果会是类似于\...\00FoundImages\"FoundImage 1.png"的东西;因此像0x22%DEST%\@file0x221这样引用整个表达式会导致命令解释器中的文件名FoundImage 1.png未被引用;使用0x22%DEST%0x22\@file1会导致"\...\00FoundImages"\"FoundImage 1.png",这不会影响许多命令,但可能会影响一些命令,而且不太美观;为了解决这个问题,首先通过cd /d 0x22%DEST%0x221更改到目录%DEST%,这样它就能单独声明,然后只在move命令行中使用@file
  • 最后,forfiles返回匹配的文件和目录,因此为了确保只处理文件,我实现了一个if查询;

1) 0x22 表示在 forfiles /C 命令表达式中的双引号字符,并以十六进制符号表示其字符代码;我更喜欢这种指定引号的方式,因为另一种选项 \" 可能会影响命令行解释器,因为它不支持反斜杠转义,因此它会识别引号标记,这可能会无意中改变其行为。


看起来运行正常!解释得很好,我现在更明白这里发生了什么。非常感谢! - danmosa

0
for /f "delims=" %%x in ("%LIST%") do (forfiles /p "%FILESPATH%" /s /m %%x* /c "cmd /c move /y @path \"%DEST%\@file\"" 2>>errors.txt)

双引号内部的双引号是命令forfiles必须使用反斜杠进行转义。但是,不需要对其他引号(如起始文件夹的引号)进行转义。


这仍然会产生相同的错误... 错误:无效的参数/选项 - '-'。 ...破折号是目录名称(testing - Copy)的一部分。 - danmosa
forfiles 命令行中,需要在 %%X 周围加上引号(不带反斜杠)。即使不需要,放置引号也无妨。任何包含空格的字符串(对于变量而言)都需要用引号括起来。 - user6017774
使用以下命令:for /f "delims=" %%x in ("%LIST%") do (forfiles /p "%FILESPATH%" /s /m "%%x"* /c "cmd /c move /y @path \"%DEST%\@file\"" 2>>errors.txt)会导致以下错误:ERROR: Files of type "E:\ImageAutomationStuff\testing - Copy\imagelist.txt*" not found. - danmosa
使用 /m "%%x*" 作为你的参数中的一部分。 - user6017774
无论我在通配符的哪一侧放引号,都会返回完全相同的错误。编辑:我还应该补充说明,即使目录中没有空格,这也不再起作用。 - danmosa

0

虽然我不明白为什么你要在另一个(FOR /F)循环中嵌套FORFILES循环,但下面的代码片段应该可以解决问题:

for /f "usebackq delims=" %%x in ("%LIST%") do (
  forfiles /p "%FILESPATH%" /s /m "%%~nxx" /c "cmd /c ECHO move /y @path \"%DEST%\"\@file" 2>>errors.txt
)

注意:
  • "%FILESPATH%""%%~nxx" 中的双引号;
  • \"%DEST%\" 中的转义双引号;
  • @path@file 已经被双引号包含,因为它们是 FORFILES 命令的变量;
  • 你可能需要重新构造 /m "%%~nxx" 文件掩码(我使用 %%~nxx 文件名和扩展名,因为我不知道 %LIST% 文件内容,假设它是一个完全限定的文件名列表);
  • 重要提示move 命令仅用于调试目的,删除前面的 ECHO 以使其生效,但要在调试完成后再删除。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接