【问题标题】:Iterating through the files and extracting only if its a zip folder using a batch file遍历文件并仅在使用批处理文件的 zip 文件夹时提取
【发布时间】:2016-05-05 03:34:45
【问题描述】:

我需要遍历当前文件夹中的所有文件,并仅在其为 zip 文件时提取它们。所以我写了下面的批处理脚本。但我收到一个错误提示

"=="."zip" was unexpected at this time

下面是我写的批处理脚本。

@echo off
cd /d %~dp0
for /r %%i in (*) do if %%i "%Extension%"==".zip" (
setlocal
cd /d %~dp0
Call :UnZipFile "G:\NewUpdates\ExtractedStuff" %%i
exit /b

:UnZipFile <ExtractTo> <newzipfile>
set vbs="%temp%\_.vbs"
if exist %vbs% del /f /q %vbs%
>%vbs%  echo Set fso = CreateObject("Scripting.FileSystemObject")
>>%vbs% echo If NOT fso.FolderExists(%1) Then
>>%vbs% echo fso.CreateFolder(%1)
>>%vbs% echo End If
>>%vbs% echo set objShell = CreateObject("Shell.Application")
>>%vbs% echo set FilesInZip=objShell.NameSpace(%2).items
>>%vbs% echo objShell.NameSpace(%1).CopyHere(FilesInZip)
>>%vbs% echo Set fso = Nothing
>>%vbs% echo Set objShell = Nothing
cscript //nologo %vbs%
if exist %vbs% del /f /q %vbs%
)
pause

我在这里做错了什么?请指教。

【问题讨论】:

  • %extension% 没有特殊含义。通常,您通过if "%var%"=="whatever" 解决上述缺失变量。但是你想要%%~xi 看到for /? 的结尾寻求帮助。
  • for /f "delims=" %%A in ('dir /b /s c:\somefolder\*.zip') do echo %%Adir /?for /?
  • @Noodles',为什么是for /Ffor /R %%i in (*.zip) do 够了……
  • 您已经在for /R 循环中包含了子程序UnZipFile,但您不应该这样做;将) 放在exit /B 之前;在 ) 之前放置 endlocal 以不超过循环中 setlocal 的嵌套深度...
  • 创建和删除提取脚本会大大减慢你的脚本。你可以使用WScript.Arguments而不是%1%2并且不要在每次迭代时更改vbs文件。你可以检查还有this

标签: windows batch-file cmd zip file-extension


【解决方案1】:

您正在读取一个未定义的变量%Extension%,而您在if 语句中的== 左侧有两个表达式,这是一个语法错误。

要获取由for 循环迭代的项目的文件扩展名,请使用~x 修饰符(在命令提示符下键入for /? 以了解更多信息),例如代码中的%%~xi

if /i "%%~xi"==".zip" ( ... )

/i 开关使比较不区分大小写,此处建议这样做,因为 Windows 以相同的方式处理文件名。


但是,在您的情况下,您根本不需要 if 语句来检查文件扩展名,因为您可以让 for 完成这项工作:

for /r %%i in (*.zip) do ( ... )

此循环仅遍历 *.zip 文件。


您的代码中还有另一个问题:子例程 :UnZipFile 是循环体的一部分,因此循环内部有和 exit /b

子例程必须在循环之外。在执行call时,子程序中不知道括号内代码块的当前上下文,所以一旦出现循环结束)就不会认为它已经结束,而是出现了语法错误。因此,您需要将) 从最底部移动到新行之前 exit /b(如果将其放在之后,exit 命令将中断循环)。

由于您的循环中有setlocal,因此您还需要将endlocal(紧接在) 之前)放入,以免超过setlocal 嵌套限制。但是,如果您在循环内使用完整路径,则不需要setlocal/endlocal。相反,我会将setlocal/endlocal 移动到子例程中以本地化其中使用的环境变量。


我不确定您是否打算更改到 cd /d %~dp0 存储脚本的目录,但我认为您想要循环中当前迭代的 *.zip 文件的完整路径,对吗?如果是这样,请删除cd 命令并在您的call 命令行中使用%%~fi


最后,引用在整个代码中并不是最优的。例如,引用文件路径和名称总是一个好主意,因为它们可能包含空格或一些其他字符,这些字符被命令解释器视为分隔符或具有其他特殊含义。

此外,在子例程中,您应该引用作为参数提供的路径,并以"%~1" 访问它们,例如,以正确引用它们(输入call /? 以查看~ 会有意删除周围的引号由命令行传递)。

最好的set 语法是:set "vbs=%temp%\_.vbs";所以引号不会成为值的一部分,并且您总是有一个位置放置引号 - 即当读取(扩展)变量时,例如"%vbs%"


最后,让我推荐你使用缩进,这样代码变得更加清晰和可维护。


这里是固定代码:

@echo off
cd /d %~dp0
for /r %%i in ("*.zip") do (
    Call :UnZipFile "G:\NewUpdates\ExtractedStuff" "%%~fi"
)
exit /b

:UnZipFile <ExtractTo> <newzipfile>
    setlocal
    set vbs="%temp%\_.vbs"
    if exist "%vbs%" del /f /q "%vbs%"
     >"%vbs%" echo Set fso = CreateObject("Scripting.FileSystemObject")
    >>"%vbs%" echo If NOT fso.FolderExists("%~1") Then
    >>"%vbs%" echo fso.CreateFolder("%~1")
    >>"%vbs%" echo End If
    >>"%vbs%" echo set objShell = CreateObject("Shell.Application")
    >>"%vbs%" echo set FilesInZip=objShell.NameSpace("%~2").items
    >>"%vbs%" echo objShell.NameSpace("%~1").CopyHere(FilesInZip)
    >>"%vbs%" echo Set fso = Nothing
    >>"%vbs%" echo Set objShell = Nothing
    cscript //nologo "%vbs%"
    if exist "%vbs%" del /f /q "%vbs%"
    endlocal
    pause

【讨论】:

  • 嘿,如何将子文件夹的 zip 文件提取到子文件夹本身?目前 G:\NewUpdates\ExtractedStuff 文件夹有 3 个子文件夹,我需要将相关的 zip 文件提取到它们现在所在的文件夹中。即 G:\NewUpdates\ExtractedStuff\updater\test.zip 应该解压到 G:\NewUpdates\ExtractedStuff\updater\。我试过Call :UnZipFile %%~pi "%%~fi" 但它不起作用:(
  • 还有没有办法静默提取?我希望它覆盖现有文件而不给我任何东西
  • 我觉得call命令行应该改成解压到ZIP文件所在的文件夹:Call :UnZipFile "%%~dpi." "%%~fi";在您的尝试中,没有驱动器号 (~d),没有引号,并且在使用 ~p/~dp 时有一个尾随 \ ,这也可能导致麻烦(这就是我附加 . 的原因);我不知道如何完成静默提取,但没有提示,但是您可以通过del命令强制删除目标文件夹内容(除了ZIP本身,当然,如果它也在目标目录中)(它的/S/Q 开关也可能有帮助)...
【解决方案2】:

我的建议是通过在 for 命令中过滤压缩文件来简化对 zip 文件的搜索,而不是检查文件扩展名

使用以下命令:

for /f "tokens=*" %%a in ('dir /a:-d /b ^| findstr /r ".zip$"') do echo %%a

上面的命令会列出你目录下的所有压缩文件,现在你可以随意玩了

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多