Preciso passar um ID e uma senha para um arquivo em lotes no momento da execução, em vez de codificá-los no arquivo.
Aqui está a aparência da linha de comando:
test.cmd admin P@55w0rd > test-log.txt
Preciso passar um ID e uma senha para um arquivo em lotes no momento da execução, em vez de codificá-los no arquivo.
Aqui está a aparência da linha de comando:
test.cmd admin P@55w0rd > test-log.txt
Respostas:
Outra dica útil é usar %*
para significar "todos". Por exemplo:
echo off
set arg1=%1
set arg2=%2
shift
shift
fake-command /u %arg1% /p %arg2% %*
Quando você executa:
test-command admin password foo bar
o arquivo em lotes acima será executado:
fake-command /u admin /p password admin password foo bar
Posso ter a sintaxe um pouco errada, mas essa é a ideia geral.
shift
"aparece" o argumento da lista. A suposição do OP era que %*
apenas produziria os argumentos restantes, mas não funciona dessa maneira, como @Joey disse.
fake-command /u admin /p password admin password foo bar
. Isso foi apontado por @Joey há muitos anos.
Aqui está como eu fiz isso:
@fake-command /u %1 /p %2
Aqui está a aparência do comando:
test.cmd admin P@55w0rd > test-log.txt
O %1
aplica-se ao primeiro parâmetro a %2
(e aqui está a parte complicada) aplica-se ao segundo. Você pode ter até 9 parâmetros passados dessa maneira.
echo %1 %2
e foi desencorajada pelo caso mais simples, sem cortes e pastáveis, com a @
e a fake-command
com parâmetros, pensando que obteríamos fake-command.bat
o conteúdo mais tarde (nesse caso, o overcomplicated fake-command.bat
pode ter echo %2 %4
que ignorar os nomes dos parâmetros). Errado, idiota. TL; DR: Não seja tão burro quanto eu. 1. echo echo %1 %2 > test.bat
2 test word1 word2
. 3. Lucro.
Se você deseja manipular de forma inteligente os parâmetros ausentes, pode fazer algo como:
IF %1.==. GOTO No1
IF %2.==. GOTO No2
... do stuff...
GOTO End1
:No1
ECHO No param 1
GOTO End1
:No2
ECHO No param 2
GOTO End1
:End1
O acesso a parâmetros em lote pode ser simples com% 1,% 2, ...% 9 ou também% *,
mas apenas se o conteúdo for simples.
Não existe uma maneira simples para conteúdos complexos "&"^&
, como não é possível acessar% 1 sem produzir um erro.
set var=%1
set "var=%1"
set var=%~1
set "var=%~1"
As linhas se expandem para
set var="&"&
set "var="&"&"
set var="&"&
set "var="&"&"
E cada linha falha, pois uma delas &
está fora das aspas.
Isso pode ser resolvido com a leitura de um arquivo temporário de uma versão comentada do parâmetro.
@echo off
SETLOCAL DisableDelayedExpansion
SETLOCAL
for %%a in (1) do (
set "prompt="
echo on
for %%b in (1) do rem * #%1#
@echo off
) > param.txt
ENDLOCAL
for /F "delims=" %%L in (param.txt) do (
set "param1=%%L"
)
SETLOCAL EnableDelayedExpansion
set "param1=!param1:*#=!"
set "param1=!param1:~0,-2!"
echo %%1 is '!param1!'
O truque é habilitar echo on
e expandir o% 1 após uma rem
declaração (funciona também com %2 .. %*
).
Assim, mesmo "&"&
pode ser repetido sem produzir um erro, como é observado.
Mas para poder redirecionar a saída do echo on
, você precisa dos dois for-loops.
Os caracteres extras * #
são usados para proteger contra conteúdos como /?
(mostraria a ajuda para REM
).
Ou um sinal de intercalação ^ no final da linha pode funcionar como um caractere multilinha, mesmo depois de a rem
.
Em seguida, leia o parâmetro rem do arquivo, mas com cuidado.
O FOR / F deve funcionar com a expansão atrasada, caso contrário, o conteúdo com "!" seria destruído.
Depois de remover os caracteres extras param1
, você conseguiu.
E para usar de param1
maneira segura, habilite a expansão atrasada.
&
, sua solução funciona apenas com conteúdo simples
test.bat ^&
e falha. Só test.bat "&"
funciona, mas esse não era o meu ponto. Você não pode usar %*
, de %1
forma segura, sem a técnica REM
&
e comercial e também aspas"
Sim, e simplesmente não se esqueça de usar variáveis como %%1
ao usar if
and for
e the gang.
Se você esquecer o duplo %
, substituirá os argumentos da linha de comando (possivelmente nulos) e receberá algumas mensagens de erro bastante confusas.
if
e for
?
for %%d in (*) do echo %%d
da linha de comando:for %d in (*) do echo %d
@for %%2 in (testing) do @echo %%2 %1
em um arquivo em lotes, produz testing 1
quando é chamado com 1 ( test 1
).
%%1
não acessa um argumento de linha de comando e também está errado para o IF
comando. Somente o FOR
comando (em arquivos em lote) requer porcentagens duplas, mas mesmo assim %%1
definiria um parâmetro FOR e não acessa argumentos
Não há necessidade de complicar. É simplesmente o comando% 1% 2 parâmetros, por exemplo,
@echo off
xcopy %1 %2 /D /E /C /Q /H /R /K /Y /Z
echo copied %1 to %2
pause
A "pausa" exibe o que o arquivo em lotes fez e espera que você pressione a tecla QUALQUER. Salve isso como xx.bat na pasta do Windows.
Para usá-lo, digite, por exemplo:
xx c:\f\30\*.* f:\sites\30
Este arquivo em lote cuida de todos os parâmetros necessários, como copiar apenas arquivos mais recentes, etc. Eu o usei desde antes do Windows. Se você gosta de ver os nomes dos arquivos, conforme eles estão sendo copiados, deixe de fora o Q
parâmetro
Um amigo estava me perguntando sobre esse assunto recentemente, então pensei em postar como lidar com argumentos de linha de comando em arquivos em lotes.
Essa técnica tem um pouco de sobrecarga, como você verá, mas torna meus arquivos em lote muito fáceis de entender e rápidos de implementar. Além de apoiar as seguintes estruturas:
>template.bat [-f] [--flag] [/f] [--namedvalue value] arg1 [arg2][arg3][...]
O jist é ter o :init
, :parse
, e:main
funções.
Exemplo de uso
>template.bat /?
test v1.23
This is a sample batch file template,
providing command-line arguments and flags.
USAGE:
test.bat [flags] "required argument" "optional argument"
/?, --help shows this help
/v, --version shows the version
/e, --verbose shows detailed output
-f, --flag value specifies a named parameter value
>template.bat <- throws missing argument error
(same as /?, plus..)
**** ****
**** MISSING "REQUIRED ARGUMENT" ****
**** ****
>template.bat -v
1.23
>template.bat --version
test v1.23
This is a sample batch file template,
providing command-line arguments and flags.
>template.bat -e arg1
**** DEBUG IS ON
UnNamedArgument: "arg1"
UnNamedOptionalArg: not provided
NamedFlag: not provided
>template.bat --flag "my flag" arg1 arg2
UnNamedArgument: "arg1"
UnNamedOptionalArg: "arg2"
NamedFlag: "my flag"
>template.bat --verbose "argument #1" --flag "my flag" second
**** DEBUG IS ON
UnNamedArgument: "argument #1"
UnNamedOptionalArg: "second"
NamedFlag: "my flag"
template.bat
@::!/dos/rocks
@echo off
goto :init
:header
echo %__NAME% v%__VERSION%
echo This is a sample batch file template,
echo providing command-line arguments and flags.
echo.
goto :eof
:usage
echo USAGE:
echo %__BAT_NAME% [flags] "required argument" "optional argument"
echo.
echo. /?, --help shows this help
echo. /v, --version shows the version
echo. /e, --verbose shows detailed output
echo. -f, --flag value specifies a named parameter value
goto :eof
:version
if "%~1"=="full" call :header & goto :eof
echo %__VERSION%
goto :eof
:missing_argument
call :header
call :usage
echo.
echo **** ****
echo **** MISSING "REQUIRED ARGUMENT" ****
echo **** ****
echo.
goto :eof
:init
set "__NAME=%~n0"
set "__VERSION=1.23"
set "__YEAR=2017"
set "__BAT_FILE=%~0"
set "__BAT_PATH=%~dp0"
set "__BAT_NAME=%~nx0"
set "OptHelp="
set "OptVersion="
set "OptVerbose="
set "UnNamedArgument="
set "UnNamedOptionalArg="
set "NamedFlag="
:parse
if "%~1"=="" goto :validate
if /i "%~1"=="/?" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="-?" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="--help" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="/v" call :version & goto :end
if /i "%~1"=="-v" call :version & goto :end
if /i "%~1"=="--version" call :version full & goto :end
if /i "%~1"=="/e" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="-e" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="--verbose" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="--flag" set "NamedFlag=%~2" & shift & shift & goto :parse
if not defined UnNamedArgument set "UnNamedArgument=%~1" & shift & goto :parse
if not defined UnNamedOptionalArg set "UnNamedOptionalArg=%~1" & shift & goto :parse
shift
goto :parse
:validate
if not defined UnNamedArgument call :missing_argument & goto :end
:main
if defined OptVerbose (
echo **** DEBUG IS ON
)
echo UnNamedArgument: "%UnNamedArgument%"
if defined UnNamedOptionalArg echo UnNamedOptionalArg: "%UnNamedOptionalArg%"
if not defined UnNamedOptionalArg echo UnNamedOptionalArg: not provided
if defined NamedFlag echo NamedFlag: "%NamedFlag%"
if not defined NamedFlag echo NamedFlag: not provided
:end
call :cleanup
exit /B
:cleanup
REM The cleanup function is only really necessary if you
REM are _not_ using SETLOCAL.
set "__NAME="
set "__VERSION="
set "__YEAR="
set "__BAT_FILE="
set "__BAT_PATH="
set "__BAT_NAME="
set "OptHelp="
set "OptVersion="
set "OptVerbose="
set "UnNamedArgument="
set "UnNamedArgument2="
set "NamedFlag="
goto :eof
@ECHO OFF
:Loop
IF "%1"=="" GOTO Continue
SHIFT
GOTO Loop
:Continue
Nota: SE "%1"==""
causará problemas se%1
estiver entre aspas.
Nesse caso, use IF [%1]==[]
ou, apenas no NT 4 (SP6) e posterior, em IF "%~1"==""
vez disso.
Vamos manter isso simples.
Aqui está o arquivo .cmd.
@echo off
rem this file is named echo_3params.cmd
echo %1
echo %2
echo %3
set v1=%1
set v2=%2
set v3=%3
echo v1 equals %v1%
echo v2 equals %v2%
echo v3 equals %v3%
Aqui estão três chamadas da linha de comando.
C:\Users\joeco>echo_3params 1abc 2 def 3 ghi
1abc
2
def
v1 equals 1abc
v2 equals 2
v3 equals def
C:\Users\joeco>echo_3params 1abc "2 def" "3 ghi"
1abc
"2 def"
"3 ghi"
v1 equals 1abc
v2 equals "2 def"
v3 equals "3 ghi"
C:\Users\joeco>echo_3params 1abc '2 def' "3 ghi"
1abc
'2
def'
v1 equals 1abc
v2 equals '2
v3 equals def'
C:\Users\joeco>
FOR %%A IN (%*) DO (
REM Now your batch file handles %%A instead of %1
REM No need to use SHIFT anymore.
ECHO %%A
)
Isso faz um loop nos parâmetros do lote (% *), sejam eles citados ou não, e então ecoa cada parâmetro.
test.bat *.txt
, test.bat cat^&dog
ouTest.bat /?
Eu escrevi um script read_params simples que pode ser chamado como uma função (ou externa .bat
) e colocará todas as variáveis no ambiente atual. Não modificará os parâmetros originais porque a função está sendocall
editada com uma cópia dos parâmetros originais.
Por exemplo, dado o seguinte comando:
myscript.bat some -random=43 extra -greeting="hello world" fluff
myscript.bat
seria capaz de usar as variáveis depois de chamar a função:
call :read_params %*
echo %random%
echo %greeting%
Aqui está a função:
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
exit /B
Limitações
-force
. Você poderia usar, -force=true
mas não consigo pensar em uma maneira de permitir valores em branco sem conhecer uma lista de parâmetros antecipadamente que não terão um valor.Changelog
-
antes de parâmetros.No arquivo em lote
set argument1=%1
set argument2=%2
echo %argument1%
echo %argument2%
% 1 e% 2 retornam os valores do primeiro e do segundo argumento, respectivamente.
E na linha de comando, passe o argumento
Directory> batchFileName admin P@55w0rd
A saída será
admin
P@55w0rd
Inspirado por uma resposta em outro lugar do @Jon, criei um algoritmo mais geral para extrair parâmetros nomeados, valores opcionais e comutadores.
Digamos que queremos implementar um utilitário foobar
. Requer um comando inicial. Tem um parâmetro opcional --foo
que aceita um valor opcional (que não pode ser outro parâmetro, é claro); se o valor estiver ausente, o padrão será default
. Ele também possui um parâmetro opcional --bar
que aceita um valor necessário . Por fim, pode levar uma bandeira--baz
sem nenhum valor permitido. Ah, e esses parâmetros podem vir em qualquer ordem.
Em outras palavras, fica assim:
foobar <command> [--foo [<fooval>]] [--bar <barval>] [--baz]
Aqui está uma solução:
@ECHO OFF
SETLOCAL
REM FooBar parameter demo
REM By Garret Wilson
SET CMD=%~1
IF "%CMD%" == "" (
GOTO usage
)
SET FOO=
SET DEFAULT_FOO=default
SET BAR=
SET BAZ=
SHIFT
:args
SET PARAM=%~1
SET ARG=%~2
IF "%PARAM%" == "--foo" (
SHIFT
IF NOT "%ARG%" == "" (
IF NOT "%ARG:~0,2%" == "--" (
SET FOO=%ARG%
SHIFT
) ELSE (
SET FOO=%DEFAULT_FOO%
)
) ELSE (
SET FOO=%DEFAULT_FOO%
)
) ELSE IF "%PARAM%" == "--bar" (
SHIFT
IF NOT "%ARG%" == "" (
SET BAR=%ARG%
SHIFT
) ELSE (
ECHO Missing bar value. 1>&2
ECHO:
GOTO usage
)
) ELSE IF "%PARAM%" == "--baz" (
SHIFT
SET BAZ=true
) ELSE IF "%PARAM%" == "" (
GOTO endargs
) ELSE (
ECHO Unrecognized option %1. 1>&2
ECHO:
GOTO usage
)
GOTO args
:endargs
ECHO Command: %CMD%
IF NOT "%FOO%" == "" (
ECHO Foo: %FOO%
)
IF NOT "%BAR%" == "" (
ECHO Bar: %BAR%
)
IF "%BAZ%" == "true" (
ECHO Baz
)
REM TODO do something with FOO, BAR, and/or BAZ
GOTO :eof
:usage
ECHO FooBar
ECHO Usage: foobar ^<command^> [--foo [^<fooval^>]] [--bar ^<barval^>] [--baz]
EXIT /B 1
SETLOCAL
para que as variáveis não escapem para o ambiente de chamada.SET FOO=
, etc., caso alguém as defina no ambiente de chamada.%~1
para remover aspas.IF "%ARG%" == ""
e não IF [%ARG%] == []
porque [
e]
não brinque com valores que terminam em um espaço.SHIFT
dentro de um IF
bloco, os argumentos atuais como %~1
não são atualizados porque são determinados quando o IF
item é analisado. Você poderia usar %~1
e %~2
dentro do IF
bloco, mas seria confuso porque você tinha um SHIFT
. Você pode colocar oSHIFT
final do bloco para maior clareza, mas isso pode se perder e / ou confundir as pessoas também. Portanto, "capturar" %~1
e %~1
fora do quarteirão parece melhor.IF NOT "%ARG:~0,2%" == "--"
.SHIFT
quando você usa um dos parâmetros.SET FOO=%DEFAULT_FOO%
é lamentável, mas a alternativa seria adicionar um IF "%FOO%" == "" SET FOO=%DEFAULT_FOO%
fora do IF NOT "%ARG%" == ""
bloco. No entanto, porque isso ainda está dentro do IF "%PARAM%" == "--foo"
bloco, o %FOO%
valor teria sido avaliado e ajustado antes que você nunca entrou no bloco, de modo que você nunca iria detectar que tanto o --foo
parâmetro estava presente e também que o%FOO%
valor estava faltando.ECHO Missing bar value. 1>&2
envia a mensagem de erro para stderr.ECHO:
ou uma das variações.Crie um novo arquivo em lote (exemplo: openclass.bat) e escreva esta linha no arquivo:
java %~n1
Em seguida, coloque o arquivo em lotes, digamos, na pasta system32, vá para o arquivo de classe Java, clique com o botão direito do mouse em Propriedades, Abrir com ..., encontre o arquivo em lote, selecione-o e é isso ...
Funciona para mim.
PS: Não consigo encontrar uma maneira de fechar a janela do cmd quando fecho a classe Java. Por enquanto...
start /wait java %~n1
Solução simples (embora a pergunta seja antiga)
Test1.bat
echo off
echo "Batch started"
set arg1=%1
echo "arg1 is %arg1%"
echo on
pause
CallTest1.bat
call "C:\Temp\Test1.bat" pass123
resultado
YourLocalPath>call "C:\Temp\test.bat" pass123
YourLocalPath>echo off
"Batch started"
"arg1 is pass123"
YourLocalPath>pause
Press any key to continue . . .
Onde YourLocalPath é o caminho do diretório atual.
Para simplificar, armazene o comando param na variável e use a variável para comparação.
Não é apenas simples de escrever, mas também simples de manter; portanto, se mais tarde alguém ou você ler seu script após um longo período de tempo, será fácil entender e manter.
Para escrever código embutido: veja outras respostas.
Para usar o loop, obtenha todos os argumentos e em lote puro:
Obs: Para uso sem:?*&<>
@echo off && setlocal EnableDelayedExpansion
for %%Z in (%*)do set "_arg_=%%Z" && set/a "_cnt+=1+0" && (
call set "_arg_[!_cnt!]=!_arg_!" && for /l %%l in (!_cnt! 1 !_cnt!
)do echo/ The argument n:%%l is: !_arg_[%%l]!
)
goto :eof
Seu código está pronto para fazer algo com o número do argumento onde ele precisa, como ...
@echo off && setlocal EnableDelayedExpansion
for %%Z in (%*)do set "_arg_=%%Z" && set/a "_cnt+=1+0" && call set "_arg_[!_cnt!]=!_arg_!"
)
fake-command /u !_arg_[1]! /p !_arg_[2]! > test-log.txt
?*&<>