Jinyu Li a personal journal

装作自己是 bat 批处理的 lua 脚本

最近需要一些管理用到的程序包的工具,无奈在 Windows 下使用批处理(bat)脚本编写这些实在太麻烦了,于是便研究如何使用更友好的脚本语言。Lua 是一个轻量的程序语言,并且根据需要进行扩展,非常符合我的一些特殊使用需求,因此我便尝试用 Lua 编写管理脚本。但是,要想方便地用 .lua 扩展名脚本直接运行,还需要为系统关联扩展名到 Lua 解释器,这就导致脚本在其它机器上使用略有不便。

好在,为了解决这一问题,可以简单地写一个 script.bat 脚本,里面的内容也很简单:

lua.exe script.lua %*

这么一来,通过执行 script.bat args... 就可以得到执行 script.lua args 同样的效果。但是,这样一来,每次就需要一个 lua.exe 和两个脚本,于是便思考如何将 lua 脚本直接嵌入在 bat 文件中。

沿着这一思路,首先想到的是将脚本以字符串方式放在 bat 中,每次执行的时候写入到临时文件,然后用 lua.exe 调用。但是这么做显得不够优雅,这个临时文件的回收也比较麻烦。经过一些思考,我得到了下面的方法,可以直接在 bat 中编写 lua 脚本。并且有趣的是,这种脚本既是一个 bat 脚本,也是一个 lua 脚本。这就意味着,我们可以直接执行 script.bat ,也可以用 lua.exe script.bat 执行它,得到同样的效果。

要想这么做,只要在需要执行的 lua 脚本前面加上下面的头部就可以了:

rem = nil --[[
@echo off
lua.exe %0 %*
exit /b --]]

它的原理比较巧妙:第一行的 rem 恰好是批处理中的注释命令,因此这一行后面的所有内容都被批处理视为注释。第二行到第四行实际执行了批处理命令,其中第三行将当前的脚本重新交给 lua.exe 运行,并将全部的命令行参数原封不动传递,第四行的 exit 退出了批处理。由于批处理是按行解释执行,在 exit 之后的内容也就再也不会被批处理载入,不会引起任何的错误。

而从 lua.exe 看来,第一行将 rem 变量赋值为了空值,也就是什么事情都没有做,此后到第4行为止的内容全部是 Lua 中的块注释,因此直接被忽略,于是 lua.exe 便会将第四行之后的一切内容视作正常的 Lua 脚本执行。