Tenho um executável que recebe vários argumentos de linha de comando e quero escrever um .cmd que execute algumas verificações e depois passe todos os argumentos para o executável.
Como exemplo, veja o executável echo_args.exe
que é este aplicativo 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);
}
}
O fato de ser Rust não tem relação com a questão, mas dessa forma você pode reproduzir minha situação.
Chamando este aplicativo diretamente do PowerShell:
echo_args.exe "hello `"`"world`"`""
Impressões, como esperado:
echo_args.exe
hello ""world""
Chamando este aplicativo diretamente do prompt de comando:
echo_args.exe "hello """"world"""""
Impressões, como esperado:
echo_args.exe
hello ""world""
Em ambos os casos, é usada uma maneira correta de escapar aspas duplas, apropriada ao processador de comandos.
Entretanto, se eu escrevo um test.cmd
arquivo, encontro o problema de que ele se comporta de forma diferente quando chamado pelo PowerShell ou pelo Prompt de Comando.
A solução ingênua é:
@echo off
set exe=echo_args.exe
"%exe%" %*
E embora isso funcione quando chamado do Prompt de Comando:
test "hello """"world"""""
Não vem do PowerShell porque:
test "hello `"`"world`"`""
Agora imprime:
echo_args.exe
hello "world"
Observe que as aspas duplas são "comidas" pelo processador de comando que executa o .cmd (ou seja, cmd.exe
). Então, o Powershell passa para o hello ""world""
to cmd.exe
(como faria para echo_args.exe
) e cmd.exe
deduz as aspas duplas e passa hello "world"
para o .exe.
Agora, percebo que posso evitar isso escrevendo um test.ps1
que execute a mesma função, para que o .cmd não seja chamado pelo PowerShell, e para fins práticos isso é bom, mas minha pergunta é: existe uma maneira de escrever o .cmd para que ele se comporte corretamente, independentemente de ser iniciado cmd.exe
automaticamente com o PowerShell ou se for encontrado e executado diretamente pelo Prompt de Comando?
Detectar se cmd.exe
foi iniciado do PowerShell parece propenso a erros e complicado. E não vejo uma maneira direta de (re)construir os argumentos no .cmd que evite esse problema (já que o problema acontece essencialmente antes mesmo que o código seja executado). O que estou esquecendo? Perguntei a alguns LLMs (ChatGPT 4o e Claude Sonnet 3.5), mas eles insistem em provar sua inutilidade para problemas que exigem alguma nuance e apresentam uma série infinita de não soluções.