¿Cuál es la mejor manera de hacer una subcadena en un archivo por lotes?

192

Quiero obtener el nombre del archivo por lotes actualmente en ejecución sin la extensión de archivo.

Gracias a este enlace , tengo el nombre del archivo con la extensión ... pero ¿cuál es la mejor manera de hacer una subcadena en un archivo por lotes?

¿O hay otra forma de obtener el nombre del archivo sin la extensión?

Es seguro asumir extensiones de 3 letras en este escenario.

JosephStyons
fuente

Respuestas:

395

Bueno, para obtener el nombre de archivo de su lote, la forma más fácil sería usarlo %~n0.

@echo %~n0

generará el nombre (sin la extensión) del archivo por lotes actualmente en ejecución (a menos que se ejecute en una subrutina llamada por call). La lista completa de tales sustituciones "especiales" para nombres de ruta se puede encontrar con help for, al final de la ayuda:

Además, se ha mejorado la sustitución de referencias variables FOR. Ahora puede usar la siguiente sintaxis 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

Los modificadores se pueden combinar para obtener resultados compuestos:

%~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

Sin embargo, para responder con precisión a su pregunta: las subcadenas se realizan utilizando la :~start,lengthnotación:

%var:~10,5%

extraerá 5 caracteres de la posición 10 en la variable de entorno %var%.

NOTA: El índice de las cadenas está basado en cero, por lo que el primer carácter está en la posición 0, el segundo en 1, etc.

Para obtener subcadenas de variables de argumento como %0, %1etc., debe asignarlas a una variable de entorno normal usando setprimero:

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

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

La sintaxis es aún más poderosa:

  • %var:~-7% extrae los últimos 7 caracteres de %var%
  • %var:~0,-4%extraería todos los caracteres, excepto los últimos cuatro, que también lo eliminarían de la extensión del archivo (suponiendo tres caracteres después del punto [ .]).

Consulte help setpara más detalles sobre esa sintaxis.

Joey
fuente
31
La extracción de subcadenas tampoco funciona con las variables de bucle FOR, por lo que tendrá que hacer lo siguiente (\ r \ n en los saltos de línea medios del código porque SO parece no permitir saltos de línea en los comentarios):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 qué tienes que hacer esto para los FORbucles?
Bob
44
@Adrian, ¿por qué no? FORes una construcción fundamental en archivos por lotes que realiza una gran cantidad de tareas diferentes. Por cierto, hay una forma más de hacer frente a la tarea mediante el uso de una subrutina, es decirfor /f %%s in ('set') do call :DoSmth "%%s" \r\n ... \r\n :DoSmth \r\n set var=%1 \r\n echo %var:~1,3%
viernes
1
usando Windows server 12 R2,% date% parece 21/05/18 (cultura de TI); la cadena correcta es: %date:~0,2%%date:~3,2%%date:~6,4%%time:~0,2%%time:~3,2%%time:~6,2%
Phate01
@ Phate01, no use %date%para construir una fecha en un formato determinado. El formato es específico para la cultura del usuario y puede cambiar. Utilice WMI en su lugar para obtener la fecha y la hora en un formato útil que no depende de la configuración del usuario. Tampoco estoy seguro de qué está haciendo este comentario aquí, ya que esta pregunta no se refería a la fecha ni a la hora.
Joey
38

Bien explicado arriba!

Para todos aquellos que pueden sufrir como yo para que esto funcione en un Windows localizado (el mío es XP en eslovaco), puede intentar reemplazarlo %con un!

Entonces:

SET TEXT=Hello World
SET SUBSTRING=!TEXT:~3,5!
ECHO !SUBSTRING!
BrandonSk
fuente
27
Tenga en cuenta que esto solo funcionará después del setlocal ENABLEDELAYEDEXPANSIONcomando
viernes
13

Como información adicional a la respuesta de Joey, que no se describe en la ayuda de set /?ni for /?.

%~0se expande al nombre del propio lote, exactamente como se escribió.
Entonces, si comienza su lote, se expandirá como

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

Pero hay una excepción, expandir en una subrutina podría fallar

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

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

Esto da como resultado

main - myBatch
Func - :myFunction
func - mybatch

En una función se %~0expande siempre al nombre de la función, no del archivo por lotes.
¡Pero si usa al menos un modificador, mostrará el nombre de archivo nuevamente!

jeb
fuente