萝卜L

导航

通过批处理快捷方式参数化调用 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.cpatharg[-1]where lua 等),但这部分不影响参数接收的核心逻辑。

快捷方式设置示例

  1. 创建 Pass_Arg_WorkDirectory_To_Lua.bat 的快捷方式 Pass_Arg_WorkDirectory_To_Lua - 快捷方式.bat

  2. 右键快捷方式 → 属性

  3. 起始位置:填写希望传递的工作目录,例如 C:\data\input
    若留空,则工作目录自动为快捷方式所在的文件夹

  4. 目标:在原有路径后追加参数,例如:

     
    D:\scripts\Pass_Arg_WorkDirectory_To_Lua.bat "hello" 123 --verbose
  5. 双击快捷方式运行

运行效果

当 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. 将脚本打包为独立可执行文件(推荐备选)

原理:使用工具(如 srlualuac + 解释器捆绑)将 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

(完)

posted on 2026-04-10 16:19  萝卜L  阅读(3)  评论(0)    收藏  举报