我有一个可执行文件,它接收许多命令行参数,我想编写一个 .cmd 来执行一些检查,然后将所有参数传递给可执行文件。
echo_args.exe
以这个 Rust 应用程序的可执行文件为例:
use std::env;
fn main() {
// Collect the command line arguments into a vector
let args: Vec<String> = env::args().collect();
// Iterate over the arguments and print each one
for arg in args.iter() {
println!("{}", arg);
}
}
事实上,它是 Rust,这与问题无关,但通过这种方式你可以重现我的情况。
直接从 PowerShell 调用此应用程序:
echo_args.exe "hello `"`"world`"`""
打印结果与预期一致:
echo_args.exe
hello ""world""
直接从命令提示符调用此应用程序:
echo_args.exe "hello """"world"""""
打印结果与预期一致:
echo_args.exe
hello ""world""
在这两种情况下,都使用了适合命令处理器的正确的转义双引号的方法。
但是,如果我写入一个test.cmd
文件,我会遇到一个问题,即从 PowerShell 或命令提示符调用时它的行为会有所不同。
简单的解决方案是:
@echo off
set exe=echo_args.exe
"%exe%" %*
尽管从命令提示符调用时它可以工作:
test "hello """"world"""""
它不支持 PowerShell,因为:
test "hello `"`"world`"`""
现在打印:
echo_args.exe
hello "world"
请注意,双引号会被运行 .cmd 的命令处理器“吃掉”(即cmd.exe
)。因此,Powershell 会传递hello ""world""
to cmd.exe
(就像传递 to 一样echo_args.exe
),并对cmd.exe
双引号进行重复数据删除,然后传递hello "world"
给 .exe。
现在,我意识到我可以通过编写执行相同功能的代码来避免这种情况,这样test.ps1
.cmd 就不会从 PowerShell 调用,从实际目的来看这很好,但我的问题是:有没有办法编写 .cmd 使其正常运行,无论它是使用 PowerShell 自动启动cmd.exe
,还是直接从命令提示符中找到并执行?
检测是否cmd.exe
从 PowerShell 启动似乎容易出错且复杂。而且我没有看到一种简单的方法来(重新)构造 .cmd 中的参数以避免此问题(因为问题本质上发生在该代码运行之前)。我错过了什么?我问过几个法学硕士(ChatGPT 4o 和 Claude Sonnet 3.5),但他们坚持证明它们对于需要一些细微差别的问题毫无用处,并提出了无数非解决方案。