BATCH FOR 循环但从特定文件开始
BATCH FOR-loop but start with specific file
我在Windows10 中有多个文件夹,每个文件夹包含多个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
循环,它只迭代匹配模式 FirstFile-*.pdf
的第一个文件(预计只有一个匹配)。该文件可以排除在另一个已经存在的 for
循环中。见代码中的解释性rem
注释:
@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
@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
我只是将文件名添加到字符串 a
的开头,如果文件名以“First”开头,如果不是,则将文件名添加到字符串的末尾 a
。我还实施了@aschipfl 建议的其他一些小改动。
我在Windows10 中有多个文件夹,每个文件夹包含多个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
循环,它只迭代匹配模式 FirstFile-*.pdf
的第一个文件(预计只有一个匹配)。该文件可以排除在另一个已经存在的 for
循环中。见代码中的解释性rem
注释:
@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
@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
我只是将文件名添加到字符串 a
的开头,如果文件名以“First”开头,如果不是,则将文件名添加到字符串的末尾 a
。我还实施了@aschipfl 建议的其他一些小改动。