通过批处理快捷方式参数化调用 Lua 脚本:完整方案与备选方式
一、核心方案:批处理作为参数转发器
目标
-
通过快捷方式启动一个批处理文件(
Pass_Arg_WorkDirectory_To_Lua.bat) -
批处理自动调用同目录下的 Lua 脚本(
Read_Arg_WorkDirectory.lua,见后) -
将快捷方式设置的“起始位置”(即工作目录)传递给 Lua 脚本
-
将快捷方式“目标”中附加的所有参数原样传递给 Lua 脚本
批处理代码(Pass_Arg_WorkDirectory_To_Lua.bat)
@echo off
set "SCRIPT_NAME=Read_Arg_WorkDirectory.lua"
REM 获取批处理所在目录(固定位置)
set "SCRIPT_DIR=%~dp0"
REM 拼接完整脚本路径
set "SCRIPT_PATH=%SCRIPT_DIR%%SCRIPT_NAME%"
REM 调用 lua.exe,传递:
REM 1. Lua 脚本的完整路径
REM 2. 可选,冗余,当前工作目录(%cd%,即快捷方式的“起始位置”)
REM 3. 快捷方式附加的所有参数(%*)
lua.exe "%SCRIPT_PATH%" "%cd%" %*
REM 调试时可取消下面注释
REM echo lua.exe "%SCRIPT_PATH%" "%cd%" %*
REM pause
参数传递映射关系
| 批处理中的变量 | 含义 | 对应 Lua 脚本中的接收位置 |
|---|---|---|
%~dp0 |
批处理所在目录 | 无,用于计算脚本所在位置 |
%cd% |
当前工作目录(快捷方式“起始位置”或快捷方式所在目录) | arg[1] |
%* |
快捷方式附加的所有参数(如 arg1 arg2 "hello world") |
arg[2], arg[3] … |
Lua 脚本如何接收并显示这些信息
Read_Arg_WorkDirectory.lua 实现:
-
获取工作目录:通过
io.popen("cd")或lfs.currentdir()显示当前目录(即批处理中%cd%传递的值) -
获取命令行参数:直接打印
arg表,其中:-
arg[0]= 脚本自身完整路径 -
arg[1]= 批处理传入的工作目录(%cd%) -
arg[2]、arg[3]… = 快捷方式附加的参数
-
脚本同时包含了对 Lua 解释器路径的探测(通过 package.cpath、arg[-1]、where lua 等),但这部分不影响参数接收的核心逻辑。
快捷方式设置示例
-
创建
Pass_Arg_WorkDirectory_To_Lua.bat的快捷方式Pass_Arg_WorkDirectory_To_Lua - 快捷方式.bat -
右键快捷方式 → 属性
-
起始位置:填写希望传递的工作目录,例如
C:\data\input
若留空,则工作目录自动为快捷方式所在的文件夹 -
目标:在原有路径后追加参数,例如:
D:\scripts\Pass_Arg_WorkDirectory_To_Lua.bat "hello" 123 --verbose -
双击快捷方式运行
运行效果
当 Lua 脚本执行时,会输出类似:
Working Directory:
from CMD: C:\data\input
from LFS: C:\data\input
Command Line Arguments (`arg` table):
arg[0]: D:\scripts\Read_Arg_WorkDirectory.lua
arg[1]: C:\data\input
arg[2]: hello
arg[3]: 123
arg[4]: --verbose
二、备选方式:
1. 快捷方式直接指向 .lua 文件(有限支持)
- 可为 Lua 脚本创建自定义扩展名(例如
.luae),并将其文件类型关联到lua.exe。 -
可改变工作目录:通过“起始位置”设置 ✅
-
可传递参数:❌ 无法传递(双击时相当于
lua.exe script.lua,无额外参数) -
结论:仅当不需要参数时可使用。
2. 硬链接与符号链接(不支持参数传递)
经过测试(Windows + Lua 5.3):
| 链接类型 | 能否改变工作目录 | 能否改变 arg[0] |
能否传递参数(双击) |
|---|---|---|---|
| 硬链接 | ✅ 是 | ✅ 是(变为链接路径) | ❌ 否 |
| 符号链接 | ❌ 否 | ❌ 否(仍为原始文件路径) | ❌ 否 |
3. 将脚本打包为独立可执行文件(推荐备选)
原理:使用工具(如 srlua、luac + 解释器捆绑)将 Lua 脚本与解释器打包成一个 .exe 文件。
亦可编译个最小引导lua用的exe。
优势:
-
快捷方式可以直接指向该
.exe文件 -
通过快捷方式的“起始位置”设置工作目录 ✅
-
通过快捷方式“目标”附加参数 ✅(参数会原样传递给 Lua 脚本)
-
无需依赖外部
lua.exe,便于分发。
三、方案对比
| 方式 | 工作目录 | arg[0] |
参数传递 | 适用性 |
|---|---|---|---|---|
快捷方式直接指向 .luae |
✅ 可设置 | ❌ 指向目标文件 | ❌ 不支持 | 差 |
| 硬链接 | ✅ 链接所在目录 | ✅ 链接名 | ❌ 不支持 | 良 |
| 符号链接 | ❌ 原始文件目录 | ❌ 原始文件名 | ❌ 不支持 | ❌ 不可用 |
| 批处理 + 快捷方式 | ✅ 完全可控 | ✅ 批处理路径 | ✅ 完整支持 | ✅ 推荐方案 |
| 打包/编译 + 快捷方式 | ✅ 完全可控 | ✅ 文件路径 | ✅ 完整支持 | ✅ 推荐方案 |
四、Lua 脚本 示例
Read_Arg_WorkDirectory.lua
print("=== Lua 5.3 Runtime Info ===")
local Is_Test = ((not ...) and arg[-1]=="io.stdout:setvbuf('no')") --zeroBraneStudio (ZBS) IDE调用时
or true
local lua_exe_dir do
if Is_Test then
print("package.cpath",package.cpath)
-- package.cpath ;C:\Users\User\Documents\GitHub\ZeroBraneStudio\bin\?.dll;..
end
local function get_lua_exe_dir_from_cpath()
for path in (package.cpath .. ";"):gmatch("([^;]*);") do
-- 匹配类似 "C:\...\bin\?.dll" 的模式
local dir = path:match("^(.*)[\\/]%?%.dll$")
if dir then
-- 检查 lua.exe 是否存在
local exe_path = dir .. "\\lua.exe"
local f = io.open(exe_path, "r")
if f then
f:close()
return dir
end
end
end
return nil
end
--------
local function get_lua_exe_dir_from_error_message()
-- 不可行。
-- `pcall(error)`结果不同于ZBS下`error`。
local ok, err = pcall(function()
error('manual error')
end)
if Is_Test and false then
print("err",err)
end
assert(not ok and type(err) == "string")
-- 错误消息示例: "lua.exe: script.lua:3: module ... not found"
return err:match([[(.-)\.*%.exe:]]) or nil
end
--------
local function get_lua_exe_dir_from_arg()
return arg[-1]:match([[(.+)\.-%.exe]]) or nil
end
--------
local function get_lua_exe_dir_from_path()
local f = io.popen('where lua 2>nul')
if f then
local path = f:read("*l")
f:close()
if path and path ~= "" then
return path:match([[(.+)\]]) or nil
end
end
return nil
end
--------
lua_exe_dir=get_lua_exe_dir_from_cpath() or get_lua_exe_dir_from_arg() or get_lua_exe_dir_from_path() or get_lua_exe_dir_from_error_message()
print("lua_exe_dir",lua_exe_dir)
if Is_Test then
print('',"get_lua_exe_dir_from_cpath",get_lua_exe_dir_from_cpath())
print('',"get_lua_exe_dir_from_error_message",get_lua_exe_dir_from_error_message())
print('',"get_lua_exe_dir_from_path",get_lua_exe_dir_from_path())
print('',"get_lua_exe_dir_from_arg",get_lua_exe_dir_from_arg())
end
end
do-- 输出当前工作目录
-- 加载 lfs 库(LuaFileSystem)
local function get_current_working_dir()
local sep = package.config:sub(1, 1) -- Windows 返回 '\',Unix 返回 '/'
local cmd = (sep == "\\") and "cd" or "pwd"
local f = io.popen(cmd)
if not f then
return nil, "无法执行命令: " .. cmd
end
local dir = f:read("*l")
f:close()
return dir
end
local cwd = get_current_working_dir() or "获取失败"
print("Working Directory:")
print('',"from CMD: ",cwd)
package.path=''
package.cpath=lua_exe_dir..[[\?.dll;]]..lua_exe_dir..[[\clibs53\?.dll]]
-- '.' is working directory - '.lua' script (not 'lua.exe')
local lfs = require("lfs")
print('',"from LFS: ",lfs.currentdir())
end
do-- 输出命令行参数表 arg
print("Command Line Arguments (`arg` table):")
if Is_Test then
print(string.format(" %-10s %s", "arg[-1]:", tostring(arg[-1] or "nil")))
-- ZBS: "io.stdout:setvbuf('no')"
-- CMD: '..\lua53.exe'
end
print(string.format(" %-10s %s", "arg[0]:", tostring(arg[0] or "nil")))
if #arg == 0 then
print(" (no arguments passed)")
else
for i = 1, #arg do
print(string.format(" arg[%d]: %s", i, tostring(arg[i])))
end
end
end
if arg[-1]=="io.stdout:setvbuf('no')"--[[from ZBS]] then
else--from CMD
--防止窗口立即关闭
-- print("\npress anykey to continue...")
-- io.read(1)
end
(完)
浙公网安备 33010602011771号