我不感到內疚,現在回答這個問題功課的學期早已過去。 Print folders and files recursively using Windows Batch是一個封閉的重複問題,討論分配。
我最初的解決方案非常簡單。有幾個技巧可以確保它能正確處理其中包含特殊字符的路徑,但不會太花哨。唯一的另一個技巧是用空格填充文件大小,以便SORT正常工作。
就像在原來的問題中,第一個參數應該是一個文件夾路徑(。\工作得很好),並且隨後的參數表示文件名(通配符都可以)。
@echo off
setlocal disableDelayedExpansion
set tempfile="%temp%\_mysort%random%.txt"
set "root="
for %%F in (%*) do (
if not defined root (
pushd %%F || exit /b
set root=1
) else (
echo(
echo %%~nxF
echo --------------------------------------------
(
@echo off
for /f "eol=: delims=" %%A in ('dir /s /b "%%~nxF"') do (
set "mypath=%%~dpA"
set "size= %%~zA"
setlocal enableDelayedExpansion
set "size=!size:~-12!"
echo !size! !mypath!
endlocal
)
) >%tempfile%
sort /r %tempfile%
)
)
if exist %tempfile% del %tempfile%
if defined root popd
我希望避免創建一個臨時文件,通過直接替換重定向和隨後的排序管道進行排序。但這不起作用。 (請參閱我的相關問題:Why does delayed expansion fail when inside a piped block of code?)
我的第一個解決方案運行良好,除了根據提供的輸入有可能產生重複輸出。我決定編寫一個能夠清除重複文件報告的版本。
基本前提很簡單 - 將所有輸出保存爲一個臨時文件,並將文件名添加到已排序字符串的前面。然後,我需要遍歷結果並僅在文件和/或路徑更改時打印信息。
最後一個循環是最棘手的部分,因爲文件名可以包含像!
^
&
和%
特殊字符可能導致問題取決於使用何種類型的擴展。我需要在循環中設置和比較變量,這通常需要延遲擴展。但是,當找到!
時,延遲擴展會導致FOR變量擴展出現問題。我可以通過調用外部循環來避免延遲擴展,但是隨後FOR變量變得不可用。我可以將變量作爲參數傳遞給CALLed例程而不會延遲擴展,但是隨後我遇到了%
^
和&
的問題。我可以用SETLOCAL/ENDLOCAL玩遊戲,但是我需要擔心通過ENDLOCAL屏障傳遞值,這需要一個相當複雜的轉義過程。問題成爲一個巨大的惡性循環。
另一個自我強加的約束是我不想用引號括起文件和路徑輸出,這意味着我必須使用延遲擴展,FOR變量或轉義值。
我發現了一個有趣的解決方案,它利用了FOR變量的奇特功能。
通常,FOR變量的範圍嚴格限於循環內。如果您在循環外調用,則FOR變量值不再可用。但是,如果您在被調用的過程中發出FOR語句 - 調用者FOR變量將再次變爲可見!問題解決!
@echo off
setlocal disableDelayedExpansion
set tempfile="%temp%\_mysort%random%.txt"
if exist %tempfile% del %tempfile%
set "root="
(
for %%F in (%*) do (
if not defined root (
pushd %%F || exit /b
set root=1
) else (
set "file=%%~nxF"
for /f "eol=: delims=" %%A in ('dir /s /b "%%~nxF"') do (
set "mypath=%%~dpA"
set "size= %%~zA"
setlocal enableDelayedExpansion
set "size=!size:~-12!"
echo(!file!/!size!/!mypath!
endlocal
)
)
)
)>%tempfile%
set "file="
set "mypath="
for /f "tokens=1-3 eol=/ delims=/" %%A in ('sort /r %tempfile%') do call :proc
if exist %tempfile% del %tempfile%
if defined root popd
exit /b
:proc
for %%Z in (1) do (
if "%file%" neq "%%A" (
set "file=%%A"
set "mypath="
echo(
echo %%A
echo --------------------------------------------
)
)
for %%Z in (1) do (
if "%mypath%" neq "%%C" (
set "mypath=%%C"
echo %%B %%C
)
)
exit /b
我已經做了一些改進,雖然我不能作出這樣找到的文件路徑的腳本。 – 2011-04-10 18:23:29
不要創建幾個平等的問題!如果需要 - 只需編輯問題。 – abatishchev 2011-04-10 18:30:45
你有沒有必要在DOS下做到這一點?如果PowerShell可用,則可能會發現在Powershell中編寫此代碼更容易,該代碼具有優良的排序和篩選功能。你不需要一個PowerShell控制檯 - 你可以直接從DOS直接運行PowerShell命令,只需調用powershell.exe並將命令或路徑傳遞給.ps1腳本 – 2011-04-19 12:37:39