bat搭配工具遍歷文件使用示例

說明

本文收集一些常用的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 /ffor /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的工具,也可以自行配置來方便編寫

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容