Windows-Server-2008

因為批量讀取文件夾時出現奇怪的行為

  • May 7, 2014

我試圖做一個簡單的批處理(這不是全部,但那是讓一切都失敗的部分)

@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
   echo %%G
   set fullpath=%%G
   set basename=%fullpath:~7%
   echo %fullpath%
   echo %basename%
)

這個腳本應該從任何地方執行,因此有趣的 for 循環。它應該瀏覽目錄,然後做一些事情。

在這個特定目錄中,還有另外 3 個目錄bomslenovodbcpatfinance

預期輸出

e:\tmp\bomslenovodb
e:\tmp\bomslenovodb
bomslenovodb
e:\tmp\cpat
e:\tmp\cpat
cpat
e:\tmp\finance
e:\tmp\finance
finance

實際輸出

First run
e:\tmp\bomslenovodb
ECHO is off.
ECHO is off.
e:\tmp\bomslenovodb
e:\tmp\cpat
ECHO is off.
ECHO is off.
e:\tmp\cpat
e:\tmp\finance
Second run
ECHO is off.
ECHO is off.
e:\tmp\finance
e:\tmp\bomslenovodb
e:\tmp\finance
ECHO is off.
e:\tmp\bomslenovodb
e:\tmp\cpat
e:\tmp\finance
Third run
ECHO is off.
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
ECHO is off.
e:\tmp\finance
e:\tmp\bomslenovodb
e:\tmp\finance
e:\tmp\finance
Fourth run
e:\tmp\bomslenovodb
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
e:\tmp\cpat
e:\tmp\finance
e:\tmp\finance
e:\tmp\finance
e:\tmp\finance

在我看來,它的set fullpath=%%G行為不符合預期,因此它的值設置不正確。

我在 Windows Server 2008 機器上,有什麼想法嗎?

經典的批處理錯誤:-)

SET 命令工作正常。失敗的是你的擴張。

%VAR%解析語句時會發生擴展,並且一次解析 FOR 循環中的所有命令。對於任何帶括號的程式碼塊也是如此。因此 和 的值%fullpath%%basename%整個 FOR 循環的執行過程中是恆定的——在進入循環之前存在的值(在這種情況下未定義)。

解決方法是使用延遲擴展,它發生在命令執行之前。延遲擴展必須先啟用,setlocal enableDelayedExpansion然後才能使用。擴展的語法更改為!VAR!.

@echo off
setlocal enableDelayedExpansion
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
   echo %%G
   set fullpath=%%G
   set basename=!fullpath:~7!
   echo !fullpath!
   echo !basename!
)

但仍然存在一個潛在問題。文件名可以包含該!字元,並且任何包含的 FOR 變數!都將在啟用延遲擴展時在擴展時損壞。解決方案是在循環內打開和關閉延遲擴展。

@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do (
   echo %%G
   set fullpath=%%G
   setlocal enableDelayedExpansion
   set basename=!fullpath:~7!
   echo !fullpath!
   echo !basename!
   endlocal
)

如果您需要保護!文字,並且您需要變數分配在迭代中保持不變,那麼最簡單的做法是使用 CALLed 過程,以便您可以使用正常擴展。只需將 FOR 變數值傳遞給 CALL 參數。但是使用 CALL 比將所有內容直接放入循環中要慢得多。

@echo off
for /f "tokens=*" %%G in ('dir /s /b /a:d "e:\tmp\*"') do call :proc "%%G"
exit /b

:proc
echo %~1
set "fullpath=%~1"
set "basename=%fullpath:~7%"
echo %fullpath%
echo %basename%
exit /b

引用自:https://serverfault.com/questions/593777