Unreal 中用了不少 .bat 脚本,因此学习一下 .bat 语法。好吧,确实属于一个古董玩意,相比于 Python,最大的好处是系统原生的支持,不需要额外配置环境。

下文以 Unreal 的 switchboard.bat 为例学习一下 .bat 语法

批处理

批处理文件(batch file)包含了一系列 DOS 命令,通常用于自动执行重复性任务。用户只需双击批处理文件便可执行任务。

关闭回显

默认情况下,bat 会显示出执行的命令,通常对于最终用户来讲,它并不是特别关心执行了什么。因此,基本上都会关闭「回显」。

1
@echo off

其中,@ 是用来屏蔽回显,因为我们使用 echo off 关闭回显的时候,同样不想输出 echo off 本身。(套娃)

setlocal 和 endlocal

setlocalendlocal 让中间的程序对于系统变量的改变只有在程序内起作用,而不会影响系统。当到达 endlocal 命令或到达批处理文件的末尾时,此程序将还原以前的设置。

1
setlocal ENABLEDELAYEDEXPANSION
  • ENABLEDELAYEDEXPANSION:启用延迟的环境变量扩展,直到遇到匹配的 endlocal 命令,而不考虑运行 setlocal 命令之前的设置。

环境变量扩展

变量名称左右加上 %,例如 %name%,就会把 name 理解为变量而不是普通字符。CMD 在读取的时候就会自动去查询对应的变量,并进行替换。这个替换值的过程,就是「变量扩展」。

例如:

1
2
set var=test
echo %var%

延迟环境变量扩展

CMD 在解释命令的时候,会把一条完整的命令进行读取,再进行匹配。bat 中,iffor 这样的命令可以加括号,将一些命令嵌套在里面执行。如果直接使用环境变量扩展,就会有问题。

1
2
3
4
5
6
7
8
set var=test

for /l %%i in (1,1,5) do (
set var=%%i
echo %var%
)

pause

打印了五个 test,证明 for /l %%i in (1,1,5) 并没有执行。

如果启用延迟环境变量扩展 ENABLEDELAYEDEXPANSION,在解释涵有嵌套格式的命令时,它会把嵌套的命令一条一条的先执行一次,然后再进行匹配操作,这样我们的赋值操作就会完成。需要注意一下,启动之后,要使用 ! 进行变量的获取。

1
2
3
4
5
6
7
8
9
10
@echo off
setlocal ENABLEDELAYEDEXPANSION
set var=test

for /l %%i in (1,1,5) do (
set var=%%i
echo !var!
)

pause

rem 与 ::

rem:: 都起到注释的作用,两者又有些不同:

  • rem 是一条命令,在运行的时候相当于把 rem 本身及其后面的内容置空。既然它是一条命令,就必须处于单独的一行或者有类似 & 的连接符号连接。
  • : 会将其后的语句识别为「标记」而不是命令语句,例如 :label,对于 :: 而言,之所以可以达到注释的效果,是因为第二个 : 不是标签的合法字符(把它换成\;. 等都行)。
1
2
3
4
5
6
REM This script optionally takes a single argument, representing the path to the desired Python
REM virtual environment directory. If omitted, it defaults to the value of %_defaultVenvDir%.
REM
REM Additionally, in the case where no argument was provided, pause on errors, in case the user
REM double-clicked the batch file and we don't want the console window to vanish inexplicably.
REM Otherwise, we exit immediately.

特殊变量

  • %*:表示参数列表
  • %0:表示脚本文件名
  • %1:第一个参数
    • %~1:第一个参数(去引号)
  • %~f0:脚本文件完整路径名
  • %~dp0:脚本文件所在目录
  • %CD%:脚本执行的 当前 目录

pushd 和 popd

存储当前目录供 popd 命令使用,然后对指定目录进行更改。压栈的操作,支持多次。

1
2
3
4
5
6
7
@echo off
rem This batch file deletes all .txt files in a specified directory
pushd %1
del *.txt
popd
cls
echo All text files deleted in the %1 directory

其它常用命令

(TODO)

使用 Robocopy 复制 Unreal Engine (UE) 游戏文件时,考虑到游戏文件通常包含大量的小文件以及大文件,推荐使用多线程复制和其他一些参数来优化速度和可靠性。以下是一个推荐的命令参数示例:

1
2
robocopy "C:\source_folder" "D:\destination_folder" /E /MT:32 /R:3 /W:5 /V /Z /FFT /XA:H /XO /XD "DerivedDataCache"
/LOG:"C:\robocopy_log.txt" /TEE

参数说明

  • "C:\source_folder""D:\destination_folder": 源文件夹和目标文件夹路径。
  • /E : 复制所有子目录,包括空目录。
  • /MT:32 : 使用 32 个线程进行多线程复制。可根据系统性能调整线程数量。
  • /R:3 : 在文件复制失败时重试 3 次。
  • /W:5 :失败重试等待时间为 5 秒。
  • /V : 详细输出模式。
  • /Z : 以可中断模式复制文件,适合网络环境不稳定的情况。
  • /FFT: 使用 FAT 文件系统时间精度(两秒),适用于不同文件系统之间的复制。
  • /XA:H : 排除隐藏文件,避免不必要的文件复制。
  • /XD : “Binaries” “DerivedDataCache”: 排除指定的目录(如 BinariesDerivedDataCache 文件夹),避免不必要的文件复制。根据你的项目结构,可以添加或修改排除的文件夹。
  • /XO: 排除较旧的文件(只复制新的或修改过的文件)。
  • /LOG : "C:\robocopy_log.txt" 将操作记录保存到指定的日志文件中,方便排查问题。
  • /TEE: 将日志同时输出到控制台和日志文件中。

应用脚本

Host 修改

备份并写入 dns 解析记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@echo off

:: Get admin privileges
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if '%errorlevel%' NEQ '0' (
echo Failed to get admin privileges
exit /b
)

:: Check if hosts file exists, create if not
set "hostsFile=%windir%\system32\drivers\etc\hosts"
if not exist "%hostsFile%" (
echo Hosts file not found, creating...
type nul > "%hostsFile%"
)

:: Backup original hosts file
copy "%hostsFile%" "%hostsFile%.bak"

:: Add hosts record
set /p ip=Enter IP address to bind (leave blank for 127.0.0.1):
if "%ip%" == "" set ip=127.0.0.1
echo %ip% campose.com >> "%hostsFile%"

:: Flush DNS cache
echo Flushing DNS cache...
ipconfig /flushdns
echo DNS cache flushed

pause

重新恢复 host 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@echo off

:: 获取管理员权限
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if '%errorlevel%' NEQ '0' (
echo Failed to get admin privileges
exit /b
)

:: 检查备份文件是否存在
set "hostsFile=%windir%\system32\drivers\etc\hosts"
set "hostsBackup=%hostsFile%.bak"
if not exist "%hostsBackup%" (
echo Backup file not found, cannot revert changes
pause
exit /b
)

:: 恢复原始hosts文件
copy "%hostsBackup%" "%hostsFile%" /Y
if not %errorlevel% == 0 (
echo Failed to revert hosts file
pause
exit /b
)

:: 刷新DNS缓存
echo Flushing DNS cache...
ipconfig /flushdns
echo DNS cache flushed

echo Hosts file reverted successfully
pause

参考资料

  1. Windows 批处理(cmd/bat)常用命令教程
  2. setlocal
  3. pushd