【问题标题】:Windows batch: REN does not halt even if errorlevel 1Windows 批处理:即使错误级别为 1,REN 也不会停止
【发布时间】:2016-01-28 14:14:57
【问题描述】:

我正在使用 REN 查找具有特定命名模式的文件并对其进行修改,如下所示:

REN "?%var1%?%var2%.S16" "?%var1%?%var3%.S16"

这会找到所有文件,如 aXaY.S16、bXaY.S16、cXbY.S16(等)并将它们重命名为 aXaZ.S16、bXaZ.S16、cXbZ.S16(等)。如果它找到它正在寻找的东西,它就可以正常工作。但是有一个问题:REN遇到错误不会停止操作。

为了证明是这样,我的脚本如下:

@echo off
set /p var1=Enter first var: 
set /p var2=Enter second var:
set /p var3=Change second var to:

echo Searching for all files matching ?%var1%?%var2%.S16

REN "?%var1%?%var2%.S16" "?%var1%?%var3%.S16"
echo Errorlevel: %errorlevel%
IF ERRORLEVEL 1 goto :FAIL
echo Success!
PAUSE
goto :eof

:FAIL
echo I done goofed!
PAUSE
exit

我在一个包含几百个文件的文件夹中运行它。我搜索了匹配 ?0?a.S16 的文件(其中有大约 40 个结果)并要求它将“a”更改为“c”,因为我知道具有此名称的文件已经存在并且应该会产生冲突。

这是控制台输出(为简洁起见):

Enter first var: 0
Enter second var:a
Change second var to:c
Searching for all files matching ?0?a.S16
A duplicate file name exists, or the file
cannot be found.
A duplicate file name exists, or the file
cannot be found.
A duplicate file name exists, or the file
cannot be found.
...(etc)...
Errorlevel: 1
I done goofed!
Press any key to continue . . .

正如预期的那样,关于重复的投诉持续了大约 40 行。但是,正如您所见,Errorlevel 在进程结束时返回 1,而不是在出现问题的第一个迹象时退出,这是我宁愿这样做的。

我确实考虑过通过 FOR /f 传递它,但我不知道如何通过它传递搜索掩码。我知道 FOR 支持 '*' 通配符,但据我所知,它不支持 '?'和 REN 一样。一种可能的替代方法是以某种方式使用正则表达式,但尽管尝试过,我还是无法完全理解它们。

有什么线索吗?非常感谢您的观看。

【问题讨论】:

  • 你的情况很混乱。 %errorlevel% is not the same as errorlevel. The first is a new local variable named errorlevel, the second is the built in ERRORLEVEL`。第一个的值不一定与第二个的值匹配,因为它们不一样。
  • 注意,感谢您提供的信息。但是脚本最终会检查 ERRORLEVEL,因此尽管出现了错误(那个 echo 只是作为调试输出,可以省略),但问题仍然存在。
  • @KenWhite:据我所知,errorlevel 变量的值与if errorlevel 命令中使用的值相同。您能否发布一个这两个值不匹配的示例?我对这个主题非常感兴趣,以便在this post 上保持准确的信息。 TIA
  • @KenWhite - 只要没有人明确定义用户定义的 ERRORLEVEL 变量,那么 OP 的代码就可以了。 %ERRORLEVEL% 将优先扩展为用户定义的环境变量值,并且仅当未定义环境变量时才会默认为所需的 ERRORLEVEL 值。

标签: windows batch-file cmd


【解决方案1】:

是的,您已经记录了 REN 命令的工作原理 - 即使重命名失败,它也会继续完成,如果至少有一次重命名失败,则报告 ERRORLEVEL 1。

如果您想在第一个错误时停止处理,那么您必须编写自己的循环来重命名每个文件,一次一个。您不应该使用简单的 FOR 循环,因为它可以在扫描整个目录之前开始迭代,因此您冒着将同一文件重命名两次的风险。安全的做法是使用 FOR /F 加上 DIR /B /A-D。

@echo off
set /p var1=Enter first var: 
set /p var2=Enter second var:
set /p var3=Change second var to:

echo Searching for all files matching ?%var1%?%var2%.S16

for /f "eol=: delims=" %%F in (
  'dir /b /a-d "?%var1%?%var2%.S16"'
) do ren "%%F" "?%var1%?%var3%.S16" || goto :break
:break
echo Errorlevel: %errorlevel%
IF ERRORLEVEL 1 goto :FAIL
echo Success!
PAUSE
goto :eof

:FAIL
echo Errorlevel: %errorlevel%
echo I done goofed!
PAUSE
exit

注意 - REN 使用的通配符规则并不直观。您应该查看How does the Windows RENAME command interpret wildcards? 以确保您获得了预期的结果。

【讨论】:

    【解决方案2】:

    ren 命令替换为

    FOR /f "delims=" %%x IN ('dir /b /a-d "%sourcedir%\?%var1%?%var2%.S16" 2^>nul') DO REN "%sourcedir%\%%x" "?%var1%?%var3%.S16"&IF ERRORLEVEL 1 ECHO failed AT %%x&goto :EOF 
    

    note 这是我测试的直接补丁,我将sourcedir 设置为测试目录。在您的情况下,您需要进行适当的调整。

    这会生成一个没有目录的基本形式的目录列表,然后将每个文件名分配给%%x 然后尝试重命名并解释生成的errorlevel。失败时,显示好措施的名称并退出。

    [编辑] 2^>nul 添加到 dir 命令中。

    这将导致dir 错误(如“找不到文件”)被定向到无处。插入符号 (^) 需要告诉 cmd >dir 命令的一部分,而不是 for

    【讨论】:

    • 感谢您的帮助。当我为我知道它找不到的文件运行它时,它给了我一般的“找不到文件”错误,但没有指定它找不到什么并且错误级别报告 0。它似乎只在文件时执行回显存在名称冲突(即它找到了我要求的文件,但无法重命名它们)。
    猜你喜欢
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    相关资源
    最近更新 更多