簡體   English   中英

為什么使用 FORFILES 執行批處理文件會導致向控制台輸出不需要的空行?

[英]Why does execution of batch file with FORFILES result in unwanted output of empty lines to console?

我寫了一個小批量代碼,它使用命令FORFILES來遍歷目錄。 操作系統為 Windows 10 Pro x64,批處理文件使用cmd.exe執行。

代碼是:

setLocal EnableDelayedExpansion
@echo off

SET LogFile=C:\logs
SET Days=1
SET Source=\\SERVER\SHARE\Folder

PUSHD %Source%
FOR /f %%a IN ('type %LogFile%\dirs.log') DO (
    MKDIR "%LogFile%\%%a" 2> NUL
    DEL %LogFile%\%%a\archive.log /Q 2>NUL
    ECHO     Collecting  %%a....
    FORFILES /P %%a /D -%Days% /C "cmd /C ECHO @RELPATH >> %LogFile%\%%a\archive.log" 2> NUL
)
POPD

批處理文件使用命令FOR從文本文件中讀取要掃描的文件夾。 此文本文件由以下批處理代碼創建:

dir.log創建批處理代碼:

PUSHD %Source%
FOR /f %%a IN ('cd') DO SET CurPath=%%a
FOR /f %%a IN ('dir /B /S /AD') DO (
    SET Directory=%%a
    SET Directory=!Directory:%CurPath%\=!
    ECHO !Directory! >> %LogFile%\dirs.log
)

POPD

文件dirs.log包含具有以下文件夾結構的文件夾列表:

Folder1
Folder2
Folder1\Subfolder1
Folder1\Subfolder2
Folder2\Subfolder1

此文本文件僅包含逐行的目錄路徑,沒有空格或任何其他對 Windows 命令解釋器具有特殊含義的字符。 因此,在第一個發布的批處理文件的FOR循環中不使用"delims="沒有問題。

FORFILES命令對來自文本文件的每個目錄路徑執行,並帶有適當的參數。

批處理文件輸出FOR的循環變量a 但是在每個批處理文件執行中,額外的空行會在ECHO Collecting %%a....的輸出行之間隨機輸出。

FORFILES在運行時將空行隨機放入控制台。

這是什么原因造成的?

此批處理代碼創建文件dirs.log並運行FORFILES ,並在運行cmd.exe到設備NUL以抑制它之前將FORFILES本身的空行輸出重定向。 FORFILES可能的錯誤輸出也通過將其從STDERR重定向到STDOUT被重定向到設備NUL來抑制。 有關詳細信息,請閱讀有關使用命令重定向運算符的 Microsoft 文章。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFilesPath=C:\logs"
set "Days=1"
set "Source=\\SERVER\SHARE\Folder"

pushd "%Source%"
if not "%CD:~-1%" == "\" ( set "CurPath=%CD%" ) else set "CurPath=%CD:~0,-1%"
del "%LogFilesPath%\dirs.log" 2>nul

setlocal EnableDelayedExpansion
rem WARNING: Directory paths with one or more exclamation marks are
rem          not correct processed by this batch code because of
rem          enabled delayed environment variable expansion.
for /F "delims=" %%I in ('dir /B /S /AD 2^>nul') do (
    set "Directory=%%I"
    set "Directory=!Directory:%CurPath%\=!"
    echo !Directory!>>"%LogFilesPath%\dirs.log"
)
endlocal

if not exist "%LogFilesPath%\dirs.log" goto ExitBatch

for /F "usebackq delims=" %%I in ("%LogFilesPath%\dirs.log") do (
    mkdir "%LogFilesPath%\%%I" 2>nul
    del "%LogFilesPath%\%%I\archive.log" 2>nul
    echo     Collecting  %%I ...
    %SystemRoot%\System32\forfiles.exe /P "%CurPath%\%%I" /D -%Days% /C "%SystemRoot%\System32\cmd.exe /C echo @RELPATH>>"%LogFilesPath%\%%I\archive.log"" >nul 2>&1
)

:ExitBatch
popd
endlocal

關於此代碼的一些注意事項:

命令SET輸出對運行set /?的幫助在命令提示符窗口中,在最后一個幫助頁面上列出了當前目錄路徑的動態環境變量CD 沒有解釋的是%CD%擴展到當前目錄路徑,末尾沒有反斜杠,但當前目錄是驅動器的根目錄。 dirs.log創建代碼中的第一個FOR命令行可以安全地替換為使用%CD%IF條件,這比在后台運行cmd.exe執行cd並捕獲其輸出的FOR循環更快。

DIR命令行由FOR在以cmd.exe /C啟動的后台命令進程中執行。 DIR可能找不到目錄,在這種情況下,會向STDERR輸出令人困惑的錯誤消息。 這就是在DIR命令行上使用2>nul的原因。 重定向運算符>必須在FOR命令行上使用脫字符^進行轉義,以便在 Windows 命令解釋器在執行命令FOR之前處理此命令行時解釋為文字字符,該命令使用在后台啟動的單獨命令進程執行嵌入式dir命令行。

echo !Directory! >>"%LogFilesPath%\dirs.log"因為這個空間也將作為尾隨空間寫入日志文件,這在此處不需要並且對剩余代碼不利。

FOR可以逐行讀取文本文件本身,跳過空行並使用默認選項跳過以分號開頭的行。 選項usebackq用於獲取用雙引號括起來的日志文件名,解釋為文件名,而不是要處理的字符串。 選項delims=定義了一個空的分隔符列表,默認情況下禁用空格/制表符上的行拆分。 在命令提示符窗口for /? 尋求有關此命令的幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM