說明
本文收集一些常用的bat搭配其它工具遍歷文件,進行一些開發的輔助性操作或輔助性開發
目錄
for循環index參數說明
當我們編寫for循環遍歷文件時,遍歷參數%%i的可變形式如下:
- %%~i - 刪除引號("),擴充 %%i
- %%~fi - 將 %%i 擴充到一個完全合格的路徑名
- %%~di - 僅將 %%i 擴充到一個驅動器號
- %%~pi - 僅將 %%i 擴充到一個路徑
- %%~ni - 僅將 %%i 擴充到一個文件名
- %%~xi - 僅將 %%i 擴充到一個文件擴展名
- %%~si - 擴充的路徑指含有短名
- %%~ai - 將 %%i 擴充到文件屬性
- %%~ti - 將 %%i 擴充到文件的日期/時間
- %%~zi - 將 %%i 擴充到文件的大小
與路徑相關的變式,可以是多種組合: - %%~dpi 顯示盤符與路徑,即父路徑
- %%~dpni 顯示盤符、路徑與文件名,不顯示后綴
- %%~dpnxi 顯示盤符、路徑與文件名,顯示后綴
dir的匹配符
-
*
包含文件和文件夾 -
*.*
僅包含文件
實例
基本遍歷
遞歸遍歷文件
可使用for /f
或for /r
兩種形式
for /f
形式需要遍歷其它目錄時,可在前后添加pushd
/pop
進行,或在dir中的匹配符前輸入目錄路徑
for /f %%i in ('dir /s /b *') do (
echo %%i
)
for /r
形式需要遍歷其它目錄時,只需將根目錄參數%cd%
替換成對應的目錄路徑或遍歷即可
for /r %cd% %%i in (*) do (
echo %%i
)
遍歷一級文件夾下的文件
此時%%i只輸出文件名。dir中的參數/a-d
是將文件夾排除在外。
for /f %%i in ('dir /b /a-d *') do (
echo %%i
)
遍歷多種類型的文件
如同時遞歸bat、cpp、sh、lua這四種類型的文件:
for /f %%i in ('dir /s /b f:\batch_files\*.bat, f:\cpp_files\*.cpp, f:\bash_files\*.sh, f:\lua_files\*.lua') do (
echo %%i
)
遞歸遍歷文件夾
使用/ad
表明只遍歷文件夾
for /f %%i in ('dir /s /b /ad *') do (
echo %%i
)
遍歷一級文件夾
使用for /d
可直接遍歷當前運行目錄下的一級文件夾
for /d %%i in (*) do (
echo %%i
)
使用for /f
形式:
for /f %%i in ('dir /b /ad *') do (
echo %%i
)
使用常量遍歷
較簡單的一種方法,則是寫定部分特定路徑,使用,
或空格
分隔這些路徑,直接通過for
循環進行遍歷。
這種方法可以經常使用。
@echo off
@REM 記得開啟延遲變量
setlocal EnableDelayedExpansion
set aDirPaths=
set "aDirPaths=!aDirPaths!,ui\aiicons"
set "aDirPaths=!aDirPaths!,ui\items"
set "aDirPaths=!aDirPaths!,ui\rideicons"
set "aDirPaths=!aDirPaths!,ui\roleicons"
for %%i in (!aDirPaths!) do (
echo %%i
)
文件操作
獲取相對路徑
替換符
=
前的變量僅能用%%
包含。替換符前可寫常量
@echo off
@REM 記得開啟延遲變量
setlocal EnableDelayedExpansion
for /r %cd% %%i in (*.*) do (
set szPath=%%i
set szRelPath=!szPath:%cd%\=!
echo !szRelPath!
)
拼接文件名
將文件名拼接到一個變量中,然后輸出到控制臺,獲取拼接結果。
如下,遍歷bat使用";"
拼接。
在拼接操作中,需將set
關鍵詞后的所有代碼使用雙引號包含。
同理,可以擴展到拼接絕對路徑、相對路徑,僅拼接文件、僅拼接文件夾等
@echo off
setlocal EnableDelayedExpansion
for /f %%i in ('dir /s /b *.*') do (
set "a=!a!;%%~nxi"
)
@REM 去掉第一個;
set a=!a:~1!
echo !a!
獲取文件時間
@echo off
setlocal EnableDelayedExpansion
for /r %cd% %%i in (*) do (
for %%a in (%%i) do set fileDate=%%~ta
echo %%i !fileDate!
)
組合操作
分布式調用
查找工程中存在的tolua.bat,并調用
for /f %%i in ('dir /s /b tolua.bat') do (
pushd %%~dpi
call tolua.bat
popd
)
搭配第三方工具
TexturePacker將png轉換成ktx
遞歸遍歷png文件,使用TexturePacker進行ktx和pvr的轉換
@echo off
setlocal EnableDelayedExpansion
@REM 配置第三方工具TexturePacker的路徑
set PATH_TEXTURE_PACKER=D:\TexturePacker\bin\TexturePacker.exe
set "szParams=!szParams! --format xml"
set "szParams=!szParams! --max-size 2048"
set "szParams=!szParams! --shape-padding 2"
set "szParams=!szParams! --border-padding 2"
set "szParams=!szParams! --disable-rotation"
set "szParams=!szParams! --algorithm MaxRects"
set "szParams=!szParams! --no-trim"
set "szParams=!szParams! --dither-fs-alpha"
set "aKtxParams=!szParams! --opt RGBA8888"
@REM 遍歷當前目錄存在的文件夾,調用自定義函數進行轉換
for /d %%i in (*) do (
echo %%i
call :function_transform_texture_set "%%i"
)
goto :end
@REM -----------------------------------------------------------------------
@REM 將png轉換成ktx的功能封裝成一個函數
:function_transform_texture_set
if "%~1" == "" goto :eof
if exist %~1.png del /q %~1.png
if exist %~1.xml del /q %~1.xml
@REM 檢查空文件夾
set szCmdOutput=
for /f "delims=" %%a in ('dir /a /b %~1') do (
set "szCmdOutput=%%a"
)
if "!szCmdOutput!" == "" (
echo %~1 is empty
rd /q %~1
del /q %~1.ktx
del /q %~1_alpha.ktx
goto :eof
)
@REM ktx
%PATH_TEXTURE_PACKER% %~1 !aKtxParams! --sheet %~1.png --data %~1.xml
goto :eof
@REM -----------------------------------------------------------------------
:end
批量進行svn mv操作
批量進行svn mv操作,能保留svn的提交記錄。
如下,將editor下所有的頭文件和cpp文件,遷移到ui文件夾下
@echo off
setlocal EnableDelayedExpansion
for /f %%i in ('dir /b ui\*.*') do (
set szSrcPurePath=editor\%%~ni
set szDstPurePath=ui\%%~ni
if exist "!szSrcPurePath!.h" svn mv !szSrcPurePath!.h !szDstPurePath!.h
if exist "!szSrcPurePath!.cpp" svn mv !szSrcPurePath!.cpp !szDstPurePath!.cpp
)
對多個倉庫進行svn cleanup
如某臺打包機,配置了多個不同的倉庫,而且有進行經常性的拉去代碼和編譯工作。在硬盤有可能出現不足時,可在jenkins上配置一份svn cleanup清理緩存,來定期減少倉庫的總大小
@echo off
setlocal EnableDelayedExpansion
set aEnvPaths=
set "aEnvPaths=!aEnvPaths! C:\env1develop"
set "aEnvPaths=!aEnvPaths! C:\env1debug"
set "aEnvPaths=!aEnvPaths! C:\env1release"
set aEnvPaths=!aEnvPaths:~1!
for %%p in (!aEnvPaths!) do (
svn cleanup %%p --include-externals
svn cleanup %%p --vacuum-pristines --include-externals
)
輔助編寫代碼
編寫xml文件
例如,遞歸遍歷將多個文件夾中的png文件,用相對路徑寫入Qt的qrc配置文件中
注意:qrc實際為xml文件,語法上存在大量的"<"、">"符號,寫入文件時,需要添加"^"進行轉義
@echo off
setlocal EnableDelayedExpansion
@REM 設置需要遍歷的所有文件夾
set aDirPaths=
set "aDirPaths=!aDirPaths!,ui\aiicons"
set "aDirPaths=!aDirPaths!,ui\items"
set "aDirPaths=!aDirPaths!,ui\rideicons"
set "aDirPaths=!aDirPaths!,ui\roleicons"
set aDirPaths=!aDirPaths:~1!
set fileOutput=res.qrc
if exist "!fileOutput!" del /q "!fileOutput!"
@REM 第一次寫入文件使用">",寫入xml的標簽頭
(
echo ^<RCC^>
echo ^<qresource prefix="/res"^>
) > "!fileOutput!"
@REM 遍歷文件寫入
for %%p in (!aDirPaths!) do (
set szDirPath=%%p
@REM 將Windows的文件分隔符"\"替換成正斜杠"/"
set szQrcPrefix=!szDirPath:\=/!
for /f %%i in ('dir /b !szDirPath!\*.png') do (
@REM 寫入配置,并增加tab以適配格式
echo ^<file^>!szQrcPrefix!/%%i^</file^> >> "!fileOutput!"
)
)
@REM 寫入xml的標簽尾
(
echo ^</qresource^>
echo ^</RCC^>
) >> "!fileOutput!"
編寫markdown中的無序列表
遞歸遍歷文件,編寫所需要跳轉的文件映射在markdown中的無序列表。運行后,從控制臺復制輸出結果到markdown中。
@echo off
setlocal EnableDelayedExpansion
for /r %%i in (*.lua) do (
set szPath=%%i
set szRelPath=!szPath:%cd%\=!
echo * [%%~nxi]^(./!szRelPath!^)
)
生成WinMerger文件
對兩個目錄結構相同的大型工程目錄,需要大量對比某些文件夾,但又不需要在全部比較時,可以編寫個遍歷腳本來批量生成,統一保存成WinMerge文件后,方便日后直接雙擊打開,無需再麻煩地拖動文件夾來對比。
@echo off
setlocal EnableDelayedExpansion
set OUTPUT_PATH=F:\WinMergeProjectsOfMiniWorld
@REM 指定兩個工程的路徑
set aEnvPaths=
set "aEnvPaths=!aEnvPaths!,C:\trunk\env1ed"
set "aEnvPaths=!aEnvPaths!,F:\trunk\env1oversea"
set aEnvPaths=!aEnvPaths:~1!
@REM 指定需要WinMerge的部分文件夾
set aSubPaths=
set "aSubPaths=!aSubPaths!,bin"
set "aSubPaths=!aSubPaths!,bin\res"
set "aSubPaths=!aSubPaths!,bin\res\ui"
set "aSubPaths=!aSubPaths!,source\client"
set "aSubPaths=!aSubPaths!,source\server"
set aSubPaths=!aSubPaths:~1!
if not exist %OUTPUT_PATH% mkdir %OUTPUT_PATH%
for %%i in (!aEnvPaths!) do (
for %%j in (!aEnvPaths!) do (
for %%k in (!aSubPaths!) do (
set szEnvLeft=
set szEnvRight=
call :function_getFolderNameFromPath szEnvLeft "%%i"
call :function_getFolderNameFromPath szEnvRight "%%j"
set szLeftPath=%%i\%%k
set szRightPath=%%j\%%k
set szFolderName=
call :function_getFolderNameFromPath szFolderName "!szLeftPath!"
set "szOutputPath=%OUTPUT_PATH%\!szFolderName! !szEnvLeft! - !szEnvRight!.WinMerge"
@REM echo szLeftPath = !szLeftPath!
@REM echo szFolderName = !szFolderName!
call :localFunction_createWinMergeProject "!szOutputPath!" "!szLeftPath!" "!szRightPath!"
)
)
)
@REM -----------------------------------------------------------------------
@REM 從路徑中獲取文件名
:function_getFolderNameFromPath
set "szPath=%~2"
if "!szPath!" == "" (
echo [ERROR] path empty
goto :eof
)
if not exist "!szPath!" (
echo [ERROR] not exist: !szPath!
goto :eof
)
pushd "!szPath!"
for /f "delims=" %%i in ('cd') do (
set szFolderName=%%~nxi
)
popd
set "%~1=!szFolderName!"
goto :eof
@REM -----------------------------------------------------------------------
@REM 創建WinMerge文件
:localFunction_createWinMergeProject
set "szOutputPath=%~1"
set "szLeftPath=%~2"
set "szRightPath=%~3"
set "szFileType=%~4"
if "!szOutputPath!" == "" (
echo [ERROR] output path empty
goto :eof
)
if "!szLeftPath!" == "" (
echo [ERROR] left path empty
goto :eof
)
if "!szRightPath!" == "" (
echo [ERROR] right path empty
goto :eof
)
if "!szLeftPath!" == "!szRightPath!" (
@REM echo [ERROR] both paths equal
goto :eof
)
if not exist "!szLeftPath!" (
@REM echo [ERROR] not exist: !szLeftPath!
goto :eof
)
if not exist "!szRightPath!" (
@REM echo [ERROR] not exist: !szRightPath!
goto :eof
)
if "!szFileType!" == "" (
set szFileType=*.*
)
if exist "!szOutputPath!" del /q "!szOutputPath!"
(
echo ^<?xml version="1.0" encoding="UTF-8"?^>
echo ^<project^>
echo ^<paths^>
echo ^<left^>!szLeftPath!^</left^>
echo ^<right^>!szRightPath!^</right^>
echo ^<filter^>!szFileType!^</filter^>
echo ^<subfolders^>1^</subfolders^>
echo ^<left-readonly^>0^</left-readonly^>
echo ^<right-readonly^>0^</right-readonly^>
echo ^</paths^>
echo ^</project^>
) >!szOutputPath!
goto :eof
@REM -----------------------------------------------------------------------
相對于其它語言的代碼,有關遍歷文件的都可以自己配置來添加常量數組、常量字符串數組、代碼等不同功能的文本
VSCode使用一鍵輸入代碼進行快速編寫
使用VSCode時,可以通過配置Snippets來完成一鍵輸入的效果,提高編寫效率。
下方貼出基本遍歷的配置代碼,供大家方便復制使用:
{
"for_f_iterate_files_recursively" : {
"scope": "bat",
"prefix": "forffr",
"body": [
"for /f %%i in ('dir /s /b *') do (",
" echo %%i",
")",
],
"description": "遞歸遍歷文件"
},
"for_r_iterate_files_recursively" : {
"scope": "bat",
"prefix": "forrfr",
"body": [
"for /r %cd% %%i in (*) do (",
" echo %%i",
")",
],
"description": "遞歸遍歷文件"
},
"for_f_iterate_files" : {
"scope": "bat",
"prefix": "forff",
"body": [
"for /f %%i in ('dir /b *') do (",
" echo %%i",
")",
],
"description": "遍歷一級文件"
},
"for_f_iterate_dirs_recursively" : {
"scope": "bat",
"prefix": "forfdr",
"body": [
"for /f %%i in ('dir /s /b /ad *') do (",
" echo %%i",
")",
],
"description": "遞歸遍歷文件夾"
},
"for_d_iterate_dirs" : {
"scope": "bat",
"prefix": "ford",
"body": [
"for /d %%i in (*) do (",
" echo %%i",
")",
],
"description": "遍歷一級文件夾"
},
"for_d_iterate_dirs" : {
"scope": "bat",
"prefix": "forfd",
"body": [
"for /f %%i in ('dir /b /ad *') do (",
" echo %%i",
")",
],
"description": "遍歷一級文件夾"
},
}
像其它如Sublime的工具,也可以自行配置來方便編寫