Quero encaminhar %*
para um script do PowerShell a partir de um script em lote, que já funciona mais ou menos. O único problema é que não consigo encaminhar argumentos com espaços corretamente.
Exemplo.bat..
@echo off
set cwd=%~dp0
set argv=%*
powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%cwd%Example.ps1' %argv%"
Exemplo.ps1..
Param(
$Message
)
If (!$Message)
{
$Message = "Hello!!!"
}
Write-Host $Message
Eu consigo fazer isso ./Example.bat Oh
muito bem, o que imprime Oh
. No entanto, ./Example.bat "Oh no"
só imprime Oh
também. ./Example "'Oh no'"
funciona, mas não é limpo, pois o uso dos scripts não é mais idêntico, o que significa que qualquer uso dele se torna fortemente acoplado, o que eu não quero.
Ao incorporar comandos do PowerShell em arquivos em lote, tome muito cuidado ao usar aspas duplas corretamente. Ao colocar todo o comando do PowerShell entre aspas duplas, você precisa converter o caractere de aspas duplas subsequente
"
para\"
Aqui está o
Example.bat
script corrigido:Não se confunda com os passos extras que segui para fazer o escape.
set argv=%argv:"=\"%
é o único passo obrigatório, as outras linhas garantem que strings vazias (sem argumentos) também sejam manipuladas corretamente.O usuário pode decidir que usar o cursor
^
é suficiente para escapar os caracteres especiais na string de entrada como esta"You ^& ^| ^> ^< ^^ I"
Caso o usuário queira inserir caracteres especiais sem símbolos de escape, uma solução mais completa é a seguinte:
Como os comentários sugerem , podemos estender a solução escapando os outros caracteres especiais para o interpretador do prompt de comando. Também podemos acrescentar que, ao dobrar as aspas, escapa o símbolo. (Não usei o
for
comando para maior clareza)Então, podemos fazer o seguinte:
A resposta útil de Fabrice SANGA explica a necessidade de escapar bem os
"
caracteres incorporados%*
e oferece uma solução que normalmente funciona, usando\"
escape.No entanto, não é robusto , porque quebra
cmd.exe
a própria análise de com"..."
argumentos fechados que contêmcmd.exe
metacaracteres como&
ou|
, por exemplo"you & I"
Atualização : A resposta vinculada foi atualizada com uma solução alternativa que tenta fornecer uma solução robusta, mas a abaixo é mais simples.
Uma solução robusta requer uma forma diferente - obscura - de escapar caracteres incorporados
"
, nomeadamente como"^""
[sic] em vez de como\"
powershell.exe
, o Windows PowerShell CLI; compwsh.exe
, o PowerShell (Core) 7 CLI, use""
Aqui está uma solução robusta e simplificada que também usa essa forma de escape para delimitar o
*.ps1
caminho de destino, de modo a lidar'
corretamente com caminhos com caracteres incorporados.Observe também o uso de
%~dpn0.ps1
, que elimina a necessidade de repetir o nome do arquivo baseExample
:setlocal
é usado para garantir que as variáveis definidas no arquivo de lote sejam delimitadas para esse arquivo; por padrão, elas seriam definidas globalmente na sessão.Uma homenagem à resposta de João Mac para o lembrete da
if defined somevar
técnica como um teste de vazio/não-existência variável, que é mais simples do queif not %somevar%.==.
Dando um passo para trás:
Se sua intenção é apenas chamar um
*.ps1
arquivo com argumentos , é melhor usar o parâmetro CLI-File
(-f
) em vez de-Command
(-c
)Fazer isso tem duas vantagens:
Isso elimina a necessidade de escape e, portanto, simplifica muito seu arquivo em lote (veja abaixo).
Ele protege seus argumentos de interpretações potencialmente indesejadas pelo PowerShell: por exemplo, com
-File
, passar literalmente$HOME
como um argumento é passado como está, enquanto com-Command
ele seria expandido como a variável automática$HOME
do PowerShell .Para obter orientações detalhadas sobre quando usar
-File
vs.-Command
, consulte esta resposta .Neste caso específico, não há necessidade de usar
%*
porque a intenção é obter apenas o primeiro parâmetro passado ao lote, e não todos os parâmetros.Proponho o
Example.bat
roteiro da seguinte forma:Esta solução leva em consideração o comentário de Compo e as observações de parâmetros vazios e de escape de SANGA.
EDIÇÃO 1:
É importante não esquecer o que foi escrito antes. O código é uma proposta para atender aos mais diversos propósitos, desde aqueles usados em condições de Temperatura e Pressão Padrão (STP) até aqueles em guerra híbrida.
Existem algumas estratégias para executar Batch em pastas com caracteres especiais. Eu uso
pushd
epopd
. Assim, a proposta de código foi alterada para atender à primeira parte do comentário do Mofi.Já a segunda parte do comentário, funcionou com a seguinte linha de comando (com prompt):
D:\Usuários\Botafogo>
"D:\Temp\teste\botafogo é campeão — desenvolvimento e teste 100% (!) com 'nome feio' e `nome bonito` bênção よろしくお願いいたします。\example.bat"
"Hello world! & Does that work? See the second edition. ;) 😉"
Quanto a um
BAT
arquivo para invocar outroPS1
arquivo, tentei seguir a solicitação da mensagem original. Só peço que não me vejam como um inimigo, mas como alguém que busca ajudar os outros.EDIÇÃO 2:
Para trabalhar com
metacharacters
(escapando"
como"^""
), com base na resposta de mklement0.Usei um tradutor online. Peço desculpas por não ser fluente no idioma.
Estou um pouco perdido quanto ao objetivo deste exercício.
parece "funcionar" para mim, dado meu entendimento da pergunta original, mas tenho certeza de que não "funcionará" com alguns outros símbolos que podem ou não ser significativos dependendo se os argumentos fornecidos são como sugeridos (
Oh
,Oh no
,"Oh no"
) ou se espera que sejam reproduzidos universalmente, literalmente.(Renomeei o
.ps1
arquivo porque prefiro manter todos os meus dados de resposta juntos sob o número da pergunta SO)