Qual é a melhor maneira de fazer uma substring em um arquivo em lotes?

192

Desejo obter o nome do arquivo em lotes atualmente em execução sem a extensão do arquivo.

Graças a este link , tenho o nome do arquivo com a extensão ... mas qual é a melhor maneira de fazer uma substring em um arquivo em lotes?

Ou existe outra maneira de obter o nome do arquivo sem a extensão?

É seguro assumir três extensões de letra nesse cenário.

JosephStyons
fonte

Respostas:

395

Bem, para obter o nome do arquivo do seu lote, a maneira mais fácil seria usar %~n0.

@echo %~n0

produzirá o nome (sem a extensão) do arquivo em lotes atualmente em execução (a menos que seja executado em uma sub-rotina chamada por call). A lista completa dessas substituições "especiais" para nomes de caminhos pode ser encontrada help forno final da ajuda:

Além disso, a substituição das referências de variáveis ​​FOR foi aprimorada. Agora você pode usar a seguinte sintaxe opcional:

%~I         - expands %I removing any surrounding quotes (")
%~fI        - expands %I to a fully qualified path name
%~dI        - expands %I to a drive letter only
%~pI        - expands %I to a path only
%~nI        - expands %I to a file name only
%~xI        - expands %I to a file extension only
%~sI        - expanded path contains short names only
%~aI        - expands %I to file attributes of file
%~tI        - expands %I to date/time of file
%~zI        - expands %I to size of file
%~$PATH:I   - searches the directories listed in the PATH
               environment variable and expands %I to the
               fully qualified name of the first one found.
               If the environment variable name is not
               defined or the file is not found by the
               search, then this modifier expands to the
               empty string

Os modificadores podem ser combinados para obter resultados compostos:

%~dpI       - expands %I to a drive letter and path only
%~nxI       - expands %I to a file name and extension only
%~fsI       - expands %I to a full path name with short names only

Para responder com precisão à sua pergunta, no entanto: Substrings são feitas usando a :~start,lengthnotação:

%var:~10,5%

extrairá 5 caracteres da posição 10 na variável de ambiente %var%.

NOTA: O índice das seqüências de caracteres é baseado em zero, portanto, o primeiro caractere está na posição 0, o segundo em 1, etc.

Para obter substrings de variáveis ​​de argumento como %0, %1etc., você deve atribuí-las a uma variável de ambiente normal usando setprimeiro:

:: Does not work:
@echo %1:~10,5

:: Assign argument to local variable first:
set var=%1
@echo %var:~10,5%

A sintaxe é ainda mais poderosa:

  • %var:~-7% extrai os últimos 7 caracteres de %var%
  • %var:~0,-4%extrairia todos os caracteres, exceto os quatro últimos, que também o livrariam da extensão do arquivo (assumindo três caracteres após o período [ .]).

Veja help setpara detalhes sobre essa sintaxe.

Joey
fonte
31
Extração substring não funciona com PARA variáveis de laço ou então você terá que fazer o seguinte (\ r \ n nos intervalos código média de linha porque SO não parecem permitir quebras de linha nos comentários):setlocal ENABLEDELAYEDEXPANSION \r\n for /f %%s in ('set') do ( \r\n set tmp=%%s \r\n echo !tmp:~-3! \r\n )
Fr0sT
@ Fr0sT Por que você tem que fazer isso para FORloops?
Bob
4
@ Adrian por que não? FORé uma construção fundamental em arquivos em lote, executando um número bastante grande de várias tarefas. Btw, há mais uma maneira de lidar com a tarefa usando uma sub-rotina, ou seja,for /f %%s in ('set') do call :DoSmth "%%s" \r\n ... \r\n :DoSmth \r\n set var=%1 \r\n echo %var:~1,3%
Fr0sT
1
usando o servidor Windows 12 R2,% date% parece 21/05/18 (cultura de TI); a corda certa é: %date:~0,2%%date:~3,2%%date:~6,4%%time:~0,2%%time:~3,2%%time:~6,2%
Phate01
@ Phate01, não use %date%para construir uma data em um determinado formato. O formato é específico da cultura do usuário e pode mudar. Use o WMI para obter data e hora em um formato útil que não depende das configurações do usuário. Também não tenho certeza do que esse comentário está fazendo aqui, pois essa pergunta não era sobre data ou hora.
Joey
38

Bem explicado acima!

Para todos os que sofrem como eu para que isso funcione em um Windows localizado (o meu é o XP em eslovaco), você pode tentar substituí-lo %por um!

Assim:

SET TEXT=Hello World
SET SUBSTRING=!TEXT:~3,5!
ECHO !SUBSTRING!
BrandonSk
fonte
27
Observe que isso funcionará somente após o setlocal ENABLEDELAYEDEXPANSIONcomando
Fr0sT 28/04
13

Como uma informação adicional à resposta de Joey, que não é descrita com a ajuda de set /?nem for /?.

%~0expande para o nome do próprio lote, exatamente como foi digitado.
Portanto, se você iniciar o lote, ele será expandido como

%~0   - mYbAtCh
%~n0  - mybatch
%~nx0 - mybatch.bat

Mas há uma exceção: expandir uma sub-rotina pode falhar

echo main- %~0
call :myFunction
exit /b

:myFunction
echo func - %~0
echo func - %~n0
exit /b

Isso resulta em

main - myBatch
Func - :myFunction
func - mybatch

Em uma função se %~0expande sempre para o nome da função, não para o arquivo em lotes.
Mas se você usar pelo menos um modificador, ele mostrará o nome do arquivo novamente!

jeb
fonte