【问题标题】:Creating a batch file - depending on variable, search for file type and extract or move创建批处理文件 - 根据变量,搜索文件类型并提取或移动
【发布时间】:2019-12-12 15:35:20
【问题描述】:

一直在尝试创建一个额外的批处理脚本来为我处理文件。我要么在 .rar 文件中发送 1 个或多个 .pdf 测试文件。

所以我的目标是:

If the first variable 1 is named 'test' then
    Is there a .rar file in the folder from variable 2 then
        Extract to a folder and then delete .rar file
    else
        check that there is a .pdf file and then copy to folder
Else
    Tell the user that neither a file or a archive has been found

我已经设法将它拼凑在一起,但我需要帮助尝试进一步扩展它以包含所有选项:

@echo off
set "cat=%1"
IF "%cat%"=="test" ( for /f %%G in ('dir *.rar /b') do set filename=%%~G)

echo %filename%

这只会给我一半的文件名,因为文件名中有空格,还需要更改第 3 行中的目录以查看发送的变量 2。

补充一下,我刚刚被告知对于 .txt 文件也是如此,倍数会以 .rar 文件的形式发送给我

【问题讨论】:

  • FOR /F 命令使用空格作为分隔符将输出与 IN 子句分开。因此,如果您想继续使用该代码,您必须使用delimis 选项告诉FOR /F 命令不要使用任何分隔符:"delims="。但是您可以只使用基本的 for 命令:FOR %%G IN (*.rar) do set filename=%%G

标签: batch-file file-extension rar


【解决方案1】:

我建议打开command prompt,运行call /? 并阅读输出帮助。帮助说明了如何从批处理文件中引用批处理文件的参数(也称为选项或参数,但不是变量)。

如果必须使用至少一个参数调用批处理文件,建议检查是否使用至少一个参数调用批处理文件,如果批处理文件在没有任何参数的情况下启动或以/? 开头,这是 Windows 上获取命令或程序帮助的默认设置。


WinRAR 控制台版本的手册是WinRAR 的程序文件夹中的文件Rar.txt。在这个文本文件中双击打开后可以看到Rar.exe可以解压一个或多个目录下的*.rar存档文件。因此,实际上没有必要使用命令 FOR。但建议此任务使用命令 FOR,因为在成功提取 RAR 存档后应删除 RAR 文件。


让我们看看 FOR 命令行 for /f %%G in ('dir *.rar /b') do 以及它在执行时的作用。

FOR 与选项 /F 处理文本文件内容或单个字符串或命令行的输出在这种情况下会导致在后台使用 %ComSpec% /c 和附加的两个' 之间的命令行。因此,由 Windows 命令进程 cmd.exe 执行,处理带有 for /F 的批处理文件如下,Windows 默认安装到 C:\Windows

C:\Windows\System32\cmd.exe /c dir *.rar /b

由单独的命令进程在后台执行的命令DIR

  • 在当前目录中搜索
  • 用于目录条目(文件或目录)
  • 匹配通配符模式*.rar
  • 并且没有设置隐藏属性(隐式默认为/A-H 选项/A 根本未指定)
  • 并输出以处理 STDOUT 以裸格式逐行匹配上述条件的找到的目录条目,这意味着仅包含没有路径的文件/文件夹名称,并且即使包含空格也不用双引号括起来或这些字符之一&()[]{}^=;!'+,`~

如果找不到任何符合搜索条件的目录条目,DIR会输出错误消息以处理后台命令进程的STDERR

FOR分别是处理批处理文件的命令进程将后台命令进程的STDERR句柄的输出重定向到它自己的STDERR句柄在这种情况下,导致它显示在控制台窗口中。但是处理启动的后台命令进程的STDOUT的输出分别由处理批处理文件的命令进程FOR捕获,并在启动的后台命令进程自行终止后逐行处理.

FOR 与选项/F 一起使用总是忽略空行。这无关紧要,因为 DIR 在使用选项 /B 执行时不会输出空行。

for /F 默认情况下将非空行拆分为子字符串,使用普通空格和水平制表符作为字符串分隔符,并默认将第一个空格/制表符分隔的字符串分配给指定的循环变量,这里是循环变量 @987654344 @。 for /F 默认情况下还会忽略已处理的行,如果拆分后的第一个子字符串以分号开头,因为 eol=; 是行尾选项的默认设置。

所以命令行for /f %%G in ('dir *.rar /b') do在处理DIR输出的目录条目列表时会出现一些问题。

  1. 对于包含空格的文件/文件夹名称,仅将文件/文件夹名称的第一个空格/制表符分隔部分分配给循环变量G,而不是完整名称。例如,像 My Archive.rar 这样的名称只会将 My 分配给循环变量 G
  2. 带有一个或多个前导空格的文件/文件夹名称被分配给循环变量G 而没有这些前导空格,这再次意味着G 不包含完整名称。例如,像   TwoLeadingSpaces.rar 这样的名称会导致分配给循环变量 G 只是 TwoLeadingSpaces.rar 没有两个前导空格,并且在引用循环变量 G 的值时找不到文件(或文件夹)。李>
  3. 命令 FOR 完全忽略在零个或多个前导空格后以分号开头的文件/文件夹名称以进行进一步处理。例如,;Test.rar(以分号开头的名称)或  ;TestWithALeadingSpace.rar(带有前导空格和分号的名称)等名称将完全被 FOR 忽略以进行进一步处理。

第 2 点和第 3 点通常没有问题,因为带有前导空格或分号开头的文件/文件夹名称非常罕见。但是带有空格的文件/文件夹名称经常出现。

一个解决方案是使用 FOR 不带选项/F:

for %%G in (*.rar) do

FOR 现在在当前目录中搜索与通配符模式*.rar 匹配的非隐藏文件(不是目录),并将找到的文件名分配给不带路径循环变量G,然后在do 之后运行命令。没有启动额外的命令进程,也没有完成子字符串拆分。

但是如果为每个找到的文件名执行的命令删除、移动或重命名与通配符模式*.rar 匹配的文件,这个非常简单的解决方案就会出现问题。与通配符模式匹配的目录条目列表在 FOR 循环主体的每次迭代中都会发生变化,而命令 FOR 在执行命令之间一个接一个地查询目录条目每个目录查询。这在 FAT16、FAT32 和 exFAT 驱动器上尤其是一个真正的问题,但也可能导致 NTFS 驱动器上出现意外行为。

每当使用 FOR 循环处理在循环迭代期间可能因删除、移动或重命名通配符模式匹配的文件而发生更改的文件列表时,最好在循环的第一次迭代之前处理完全加载到内存中的文件列表。

因此,对于需要在成功提取后删除 RAR 存档文件的任务,更好的解决方案是:

for /F "eol=| delims=" %%I in ('dir *.rar /A-D /B 2^>nul') do

DIR 选项/A-D 会导致忽略具有目录属性的目录条目。所以 DIR 的输出只是与当前目录中的通配符模式匹配的文件名,包括隐藏的 RAR 存档文件。

2^>nul2>nul 的形式传递给后台命令进程,这会导致将 DIR 在找不到 *.rar 文件时输出的错误消息重定向到设备 NUL 压制它。

阅读有关Using command redirection operators 的Microsoft 文章,了解2>nul。重定向运算符 > 必须在 FOR 命令行上使用插入字符 ^ 转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时解释为文字字符> 在后台启动的单独命令进程中执行嵌入的dir 命令行。

for /F 选项 eol=| 将行尾字符从 ; 更改为 |。根据有关 Naming Files, Paths, and Namespaces 的 Microsoft 文档,任何文件名都不能在其文件名中包含竖线。因此,由于文件结束选项,FOR 不再忽略文件名。

for /F 选项 delims= 将用于将行拆分为子字符串的分隔符列表更改为一个空的分隔符列表,从而完全禁用行拆分行为。因此,文件名中任意位置包含一个或多个空格的文件名完全分配给指定的循环变量I


任务描述对于根据批处理文件参数执行的操作不是很清楚,特别是如果第一个参数不区分大小写test

但是,如果使用第一个参数为 test 或根本没有参数或将 /? 作为第一个参数调用,以下注释批处理文件可能适用于此任务。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" goto OutputHelp
if "%~1" == "/?" goto OutputHelp
if /I not "%~1" == "test" goto MoreCode

set "SourceFolder=%~2"
if defined SourceFolder goto CheckFolder

echo/
echo Error: Folder with RAR or PDF file(s) not specified on command line.
goto OutputHelp

:CheckFolder
rem Replace all forward slashes by backslashes in folder name.
set "SourceFolder=%SourceFolder:/=\%"
rem Append a backslash to folder path if it does not end with a backslash.
if not "%SourceFolder:~-1%" == "\" set "SourceFolder=%SourceFolder%\"
rem Check the existence of the source folder.
if exist "%SourceFolder%" goto ProcessFolder

echo/
echo Error: Folder "%SourceFolder%" does not exist.
goto OutputHelp

:ProcessFolder
rem Get full qualidfied folder name, i.e. the folder name
rem with its absolute path and ending with a backslash.
for %%I in ("%SourceFolder%") do set "SourceFolder=%%~fI"

rem Define the destination folder for the PDF files extracted from the
rem RAR archive file(s) in source folder or copied from source folder.
set "DestinationFolder=C:\Temp\Test\"

rem Search for all *.rar files in folder passed with second argument and
rem extract all *.pdf files in each RAR archive file to the configured
rem destination folder. Rar.exe creates the destination folder automatically
rem if it is not already existing. The batch file is halted after processing
rem a RAR file on which Rar.exe exited with a value greater 0. Read the exit
rem codes documentation of Rar.exe at bottom of text file Rar.txt for more
rem information about the RAR exit codes. See Rar.txt also for the meaning
rem of the few RAR switches used here.

set "RarFileCount=0"
for /F "eol=| delims=" %%I in ('dir "%SourceFolder%*.rar" /A-D /B 2^>nul') do (
    set /A RarFileCount+=1
    "%ProgramFiles%\WinRAR\Rar.exe" e -cfg- -idcdp -or -- "%SourceFolder%%%I" *.pdf "%DestinationFolder%"
    if not errorlevel 1 (del /A /F "%SourceFolder%%%I") else echo/& pause
)

if %RarFileCount% == 0 goto CheckFiles
if %RarFileCount% == 1 (set "PluralS=") else set "PluralS=s"
echo/
echo Info: Processed %RarFileCount% *.rar file%PluralS% in folder "%SourceFolder%".
goto EndBatch

:CheckFiles
echo Info: There are no *.rar files in folder "%SourceFolder%".
if exist "%SourceFolder%*.pdf" goto CopyFiles

echo Info: There are no *.pdf files in folder "%SourceFolder%".
goto EndBatch

:CopyFiles
rem Copy all PDF files in source folder to destination folder. xcopy.exe
rem creates destination folder automatically if it is not already existing.
echo/
%SystemRoot%\System32\xcopy.exe "%SourceFolder%*.pdf" "%DestinationFolder%" /C /I /Y
goto EndBatch

:OutputHelp
echo/
echo Usage: %~n0 [TEST] [Folder with RAR or PDF file(s)]
echo/
echo    If the first argument is case-insensitive TEST, the second argument
echo    specifies the folder containing the RAR files to extract or the PDF
echo    files to copy to destination folder. The folder must be specified
echo    with first argument being TEST.
echo/
pause
goto EndBatch

:MoreCode
rem Add here the code to execute on first argument is not case-insensitive TEST.

:EndBatch
endlocal

要了解所使用的命令及其工作原理,请打开command prompt 窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /?
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?
  • xcopy /?
  • "%ProgramFiles%\WinRAR\Rar.exe" /?

【讨论】:

    【解决方案2】:

    你可以用这个:

    @echo off
    set "cat=%~1"
    IF "%cat%"=="test" ( 
      for %%G in (*.rar) do set filename=%%G
    )
    echo %filename%
    

    这里用通配符来获取目录下所有的rar文件。

    【讨论】:

      猜你喜欢
      • 2018-11-21
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多