【问题标题】:BATCH FOR-loop but start with specific fileBATCH FOR-loop,但从特定文件开始
【发布时间】:2021-11-15 15:11:33
【问题描述】:

我在 Windows 10 中有许多文件夹,每个文件夹都包含许多 PDF 文件。对于每个文件夹,我需要运行 GhostScript,并将文件夹的 PDF 文件作为输入,但将某个文件作为第一个文件。

每个文件夹都包含一个名为 "FirstFile-X.pdf" 的文件,其中 X 可以是任何东西,对于每个文件夹,我都需要该文件作为第一个输入。

我在批处理文件中有以下内容:

setlocal enableDelayedExpansion
set gs="C:\Program Files\gs\gs9.54.0\bin\gswin64.exe"
set options=-dNOPAUSE -q -dBATCH -sDEVICE=pdfwrite
%gs% -sDEFAULTPAPERSIZE=a4 -dBATCH
for /d %%d in (*) do (
    set a=
    set output=%%d.pdf
    for %%f in (%%d\*.pdf) do (
        set "a=!a!%%d^\%%~nxf "
    )
    %gs% %options% -sOutputFile=!output! !a!
)

上面的代码可以工作,但它不会将该特定文件作为第一个输入。是否可以让最里面的for-loop 按我需要的顺序遍历每个文件?

【问题讨论】:

    标签: for-loop batch-file cmd windows-10 nested-for-loop


    【解决方案1】:

    @aschipfl 给出的答案启发了我做一个不同的解决方案:

    @echo off
    setlocal enableDelayedExpansion
    set "gs=C:\Program Files\gs\gs9.54.0\bin\gswin64.exe"
    set "options=-dNOPAUSE -q -dBATCH -sDEVICE=pdfwrite"
    "%gs%" -sDEFAULTPAPERSIZE=a4 -dBATCH
    for /d %%d in (*) do (
        set a=
        for %%f in (%%d\*.pdf) do (
            set string=%%~nf
            if "!string:~0,5!"=="First" (
                set "a=%%f !a!"
            ) else (
                set "a=!a!%%f "
            )
        )
        "%gs%" %options% -sOutputFile=%%d.pdf !a!
    )
    endlocal
    

    如果文件名以“First”开头,我只需将文件名添加到字符串a 的开头,否则将文件名添加到字符串a 的末尾。我还实施了@aschipfl 建议的其他一些小改动。

    【讨论】:

      【解决方案2】:

      您可以使用一个额外的for 循环,它只迭代与模式FirstFile-*.pdf 匹配的第一个文件(预计只有一个匹配)。这个文件可以被排除在另一个已经存在的for 循环中。见代码中的解释remcmets:

      @echo off
      setlocal EnableExtensions EnableDelayedExpansion
      rem // Use quoted `set` syntax to assign unquoted values but still protect special characters:
      set "gs=C:\Program Files\gs\gs9.54.0\bin\gswin64.exe"
      set "options=-dNOPAUSE -q -dBATCH -sDEVICE=pdfwrite"
      rem // Use quotation during expansion of variables:
      "%gs%" -sDEFAULTPAPERSIZE=a4 -dBATCH
      
      for /D %%d in (*) do (
          set "a="
          rem // Let an extra loop find the first file:
          for %%e in ("%%d\FirstFile-*.pdf") do (
              rem /* This condition is just necessary in case more than one files are found
              rem    by the extra loop in order to avoid duplicates in the returned list: */
              if not defined a (
                  rem // Append the first file:
                  set "a=!a!%%~e "
                  rem // Iterate over all files (including first file):
                  for %%f in ("%%d\*.pdf") do (
                      rem // Exclude already processed first file at this point:
                      if /I not "%%~NXf"=="%%~NXe" set "a=!a!%%~f "
                  )
              )
          )
          rem // There is no variable `output` needed:
          "%gs%" %options% -sOutputFile=%%d !a!
      )
      endlocal
      exit /B
      

      此外,我还做了一些其他的小改进,代码中也有注释。


      请注意,此代码在目录和 PDF 文件路径包含空格以及包含字符 !^ 时仍然存在问题。为了克服它们,您需要进一步引用和切换延迟扩展:

      @echo off
      setlocal EnableExtensions DisableDelayedExpansion
      rem // Use quoted `set` syntax to assign unquoted values but still protect special characters:
      set "gs=C:\Program Files\gs\gs9.54.0\bin\gswin64.exe"
      set "options=-dNOPAUSE -q -dBATCH -sDEVICE=pdfwrite"
      rem // Use quotation during expansion of variables:
      "%gs%" -sDEFAULTPAPERSIZE=a4 -dBATCH
      
      for /D %%d in (*) do (
          set "a="
          set "output=%%d"
          rem // Let an extra loop find the first file:
          for %%e in ("%%d\FirstFile-*.pdf") do (
              rem // Store currently iterated item:
              set "item=%%~e"
              rem /* This condition is just necessary in case more than one files are found
              rem    by the extra loop in order to avoid duplicates in the returned list: */
              if not defined a (
                  rem // Toggle delayed expansion to avoid issues with `!` and `^`:
                  setlocal EnableDelayedExpansion
                  rem // Append the first file in a quoted manner:
                  set "a=!a!"!item!" "
                  rem // Transfer value `a` over `endlocal` barrier:
                  for /F "delims=" %%t in ("a=!a!") do endlocal & set "%%t"
                  rem // Iterate over all files (including first file):
                  for %%f in ("%%d\*.pdf") do (
                      rem // Store currently iterated item:
                      set "item=%%~f"
                      rem // Exclude already processed first file at this point:
                      if /I not "%%~NXf"=="%%~NXe" (
                          rem // Toggle delayed expansion to avoid issues with `!` and `^`:
                          setlocal EnableDelayedExpansion
                          rem // Append the current item in a quoted manner:
                          set "a=!a!"!item!" "
                          rem // Transfer value `a` over `endlocal` barrier:
                          for /F "delims=" %%t in ("a=!a!") do endlocal & set "%%t"
                      )
                  )
              )
          )
          rem // Eventually use delayed expansion as well as quotation:
          setlocal EnableDelayedExpansion
          "!gs!" !options! -sOutputFile="!output!" !a!
          endlocal
      )
      endlocal
      exit /B
      

      【讨论】:

      • 感谢您的回答。您的回答启发了我想出一个不需要额外嵌套 for 循环的不同解决方案。我会用新代码更新帖子。
      • 到目前为止,所有文件夹或文件名都不包含空格,但我会保存这段代码以备不时之需 :)
      • @smlange,我回滚了您的问题编辑以删除您的解决方案。请改为发布您的代码作为答案,因为这就是答案部分的用途!谢谢! N. B.: 您应该将代码中的if 条件更改为if /I "!string:~0,5!"=="First",以便区分大小写……
      • 感谢您提供有关if 的提示!我还发布了我的更新作为答案:)
      猜你喜欢
      • 1970-01-01
      • 2017-04-11
      • 1970-01-01
      • 2017-05-24
      • 1970-01-01
      • 2020-11-05
      • 1970-01-01
      • 2021-08-08
      相关资源
      最近更新 更多