batch-file - run - que es batch file en español
La comparación de archivos por lotes de variable con constante falla (2)
1. Depuración de un archivo por lotes
Para depurar un archivo por lotes para encontrar errores de sintaxis en el código, se recomienda ejecutar el archivo por lotes desde una ventana del símbolo del sistema después
echo off
modificar cada
echo off
para
echo off
echo ON
o eliminarlo del archivo por lotes o comentarlo con el comando
REM
.
De manera predeterminada, el intérprete de comandos de Windows genera cada línea de comando o un bloque de comando completo que comienza con
(
y termina con una coincidencia
)
después de analizar y preprocesar en qué variables de entorno referenciadas con
%variable%
(expansión inmediata) ya están reemplazadas por el valor actual de la variable de entorno antes ejecutando la línea de comando / bloque.
Con
@echo off
en la parte superior del archivo por lotes, este comportamiento predeterminado se desactiva, por lo que
@
al comienzo de la línea de comando desactiva también la salida de esta primera línea de comando.
Por supuesto, eso es bienvenido cuando finaliza el desarrollo del archivo por lotes y el archivo por lotes funciona bien.
Pero para la depuración de un archivo por lotes que no funciona como se esperaba, es mejor ver también las líneas de comando realmente ejecutadas por el intérprete de comandos para averiguar dónde sale inesperadamente la ejecución del archivo por lotes debido a un error.
El comportamiento de
ECHO
se explica muy brevemente en la salida de ayuda al ejecutar
echo /?
desde una ventana de símbolo del sistema.
Al abrir una ventana del símbolo del sistema, se inicia
cmd.exe
implícitamente con la opción
/K
para
mantener
el proceso de comando en ejecución y la ventana de la consola abierta después de que finaliza la ejecución de un archivo por lotes o una aplicación.
Una excepción es cuando el archivo por lotes contiene la
exit
comando sin parámetro
/B
porque en este caso el proceso de comando actual siempre sale independientemente de la jerarquía de llamada.
exit /B
es igual a
goto :EOF
y debe usarse en lugar de simplemente
exit
excepto que hay una muy buena razón para usar solo
exit
.
exit /B
y
goto :EOF
requiere ambas extensiones de comando como habilitado por defecto en Windows.
Al hacer doble clic en un archivo por lotes, se inicia
cmd.exe
con la opción
/C
para
cerrar el
proceso de comando y la ventana de la consola automáticamente cuando la ejecución de la aplicación o el archivo por lotes finaliza independientemente del motivo por el cual finalizó la ejecución de un archivo por lotes.
Este comportamiento al cerrar automáticamente la ventana de la consola no es bueno para depurar un archivo por lotes porque el mensaje de error no se puede ver cuando la ejecución del archivo por lotes finaliza debido a un error de sintaxis.
Para obtener más detalles sobre las opciones del intérprete de comandos de Windows, ejecute en una ventana del símbolo del sistema el comando:
cmd /?
Cómo salir intencionalmente de la ejecución de un archivo por lotes usando
goto :EOF
(los dos puntos aquí son importantes como excepción) o
exit /B
(solo un alias interno para
goto :EOF
) se explica en ayuda de esos dos comandos que se muestran al ejecutar
goto /?
y
exit /?
en una ventana de símbolo del sistema.
Para depurar un archivo por lotes más grande, podría ser útil usar un
goto
agregado temporalmente en la parte superior del archivo por lotes para saltar a un determinado bloque y un
goto :EOF
para salir del procesamiento por lotes después del bloque para depurar.
Por cierto:
::
es una etiqueta no válida que a menudo se usa para comentarios en archivos por lotes, ya que las líneas de etiqueta nunca se muestran en la ejecución de un archivo por lotes.
Pero en el bloque de comandos de un bucle
FOR
no se pueden usar etiquetas porque el intérprete de comandos de Windows no puede interpretar correctamente un bucle
FOR
con etiquetas dentro del bloque de comandos.
Por esa razón, es mejor usar el comando
REM
(comentario) para comentarios, ya que este comando está diseñado para comentarios en archivos por lotes y realmente funciona en cualquier parte de un archivo por lotes.
2. Error en el archivo por lotes
Al ejecutar el archivo por lotes publicado en cuestión con
@ECHO OFF
comentado reemplazándolo con
rem @echo off
(ejecute un reemplazo en el editor de texto) desde una ventana de símbolo del sistema, se puede ver fácilmente en qué línea se produce el error:
if %DiffSec% LSS 10 (ECHO "LESS 10")else %DiffSec% LSS 1 (ECHO "LESS 1")
Si el valor actual de la variable de entorno
DiffSec
no es inferior a
10
, el intérprete de comandos de Windows ejecuta la rama
ELSE,
que comienza con un número como
10
.
El intérprete de comandos de Windows no puede encontrar una aplicación con ese nombre en el directorio actual o en cualquier directorio especificado en la lista de directorios separados por punto y coma de la variable de entorno
PATH
tiene una extensión de archivo especificada en la lista de extensiones de archivos separados por punto y coma de la variable de entorno
PATHEXT
.
El error es aquí, obviamente, el comando IF faltante para la próxima comparación. Entonces el código correcto sería
if %DiffSec% LSS 10 (ECHO "LESS 10") else if %DiffSec% LSS 1 ECHO "LESS 1"
Esto sería más fácil de leer al escribir la condición en varias líneas:
if %DiffSec% LSS 10 (
ECHO "LESS 10"
) else if %DiffSec% LSS 1 (
ECHO "LESS 1"
)
La sintaxis ahora es correcta.
Pero la segunda condición no tiene sentido como
JosefZ
ya mencionó en su comentario.
Si el valor de
DiffSec
es 10 o mayor, lo que resulta en la ejecución del comando
IF
en la rama
ELSE
, esta condición definitivamente nunca es cierta.
Entonces más sentido tendría:
if %DiffSec% LSS 1 (ECHO LESS 1) else if %DiffSec% LSS 10 ECHO LESS 10
O alternativamente
if %DiffSec% LSS 1 (
ECHO LESS 1
) else if %DiffSec% LSS 10 (
ECHO LESS 10
)
Para obtener más información sobre condiciones IF ELSE válidas en archivos por lotes, consulte, por ejemplo, las respuestas en
- SI ELSE error de sintaxis dentro del archivo por lotes?
-
scripting por lotes: si existe ./sdcard/file.any usando adb
3. Agregar cero a la izquierda para números <10
Las variables de entorno son siempre de tipo cadena. Para expresiones aritméticas, el valor de cadena de una variable de entorno se convierte a un entero de 32 bits con signo, si es posible, y el resultado de la expresión aritmética se convierte de nuevo a entero de 32 bits con signo.
También una condición
IF
como
if %DiffSec% LSS 10
se expande antes de la ejecución, por ejemplo, a
if 5 LSS 10
resulta en la conversión de
5
(0x35) de cadena a entero y
10
(0x31 0x30) también de cadena a entero para comparar los dos números como enteros
Por lo tanto, sería un poco más rápido evitar dicha comparación numérica si eso fuera posible.
Es bastante fácil agregar un cero inicial a un número inferior a 10 sin probar realmente el valor mediante la sustitución de cadenas.
Primero, el valor actual de la variable de entorno se antepone con uno (para un número de dos dígitos) o más
0
(para 3, 4 o incluso más dígitos).
set "DiffSec=0%DiffSec%"
A continuación, los últimos X caracteres como 2 para un número de dos dígitos se asignan del valor actual de la variable de entorno a la variable de entorno.
set "DiffSec=%DiffSec:~-2%"
La sustitución de cadenas se explica en ayuda de la salida del comando
SET
ejecutando en una ventana del símbolo del sistema
set /?
.
El resultado de las dos líneas es que
DiffSec
tiene para valores de
0
a
99
después de esas dos líneas siempre un número de dos dígitos en el rango de
00
a
99
.
4. Análisis de una expresión aritmética.
Una interpretación aritmética que es la cadena después de
set /a
es interpretada por el intérprete de comandos de Windows completamente diferente a otras cadenas.
Los espacios y las pestañas son separadores de palabras, pero no tienen más significado especial. Por lo tanto, es aconsejable utilizar espacios para que la expresión aritmética sea más legible.
Luego, hay muchos operadores que se enumeran en la ayuda del comando
SET que se
muestra al ejecutarse en una ventana del símbolo del sistema
set /?
.
Otros enteros decimales, octales y hexadecimales se interpretan en una expresión aritmética como enteros.
Y por último, cada otra cadena se interpreta como el nombre de una variable de entorno cuyo valor actual se convierte de cadena a entero.
Por esa razón, no es aconsejable utilizar la expansión inmediata o retardada en una expresión aritmética.
El valor de referencia de una variable de entorno con
%variable%
dentro de una expresión aritmética no es bueno cuando se usa dentro de un bloque de comandos en el que el valor actual de la variable de entorno reemplaza la referencia de la variable que ya se estaba analizando en el bloque de comandos completo antes de ejecutar el primer comando.
Valor de referencia de una variable de entorno con
!variable!
dentro de una expresión aritmética tampoco es bueno porque requiere habilitar la expansión retardada, lo que resulta en el manejo de signos de exclamación en cadenas que ya no son caracteres literales.
Por lo tanto, lo mejor es simplemente escribir los nombres de las variables en una expresión aritmética sin signos de porcentaje o signos de exclamación circundantes, si eso es posible porque el nombre de la variable no contiene un carácter de espacio y comienza con un carácter que Windows no puede interpretar como un número entero. intérprete de comandos.
Vea también la respuesta en
¿Por qué no hay salida de cadena con ''echo% var%'' después de usar ''set var = text'' en la línea de comando?
para obtener detalles sobre cómo asignar un valor a una variable de entorno usando solo
set
o
set /P
(solicitud) o
set /A
(expresión aritmética).
5. Código fijo y optimizado
El código en cuestión puede repararse y optimizarse para este código:
@echo off
rem Time Calculation
for /F "skip=1 tokens=1-4" %%A in (''%SystemRoot%/System32/wbem/wmic.exe PATH Win32_LocalTime GET Day^,Hour^,Minute^,Second'') do (
set Day=%%A
set Hour=%%B
set Minute=%%C
set Second=%%D
)
set /A TimeStart=Day * 86400 + Hour * 3600 + Minute *60 + Second
@echo on
%SystemRoot%/System32/ping.exe 8.8.8.8 -n 11
@echo off
for /F "skip=1 tokens=1-4" %%A in (''%SystemRoot%/System32/wbem/wmic.exe PATH Win32_LocalTime GET Day^,Hour^,Minute^,Second'') do (
set Day=%%A
set Hour=%%B
set Minute=%%C
set Second=%%D
)
set /A TimeEnd=Day * 86400 + Hour * 3600 + Minute *60 + Second
set /A TimeDiff=TimeEnd - TimeStart
set /A DiffSec=TimeDiff %% 60
set /A TimeDiff=(TimeDiff - DiffSec) / 60
set /A DiffMin= TimeDiff %% 60
set /A DiffHrs=(TimeDiff - DiffMin) / 60
set "DiffSec=0%DiffSec%"
set "DiffSec=%DiffSec:~-2%"
set "DiffMin=0%DiffMin%"
set "DiffMin=%DiffMin:~-2%"
set "DiffHrs=0%DiffHrs%"
set "DiffHrs=%DiffHrs:~-2%"
echo Time needed for orders deletion: %DiffHrs%:%DiffMin%:%DiffSec%
Para comprender los comandos utilizados y cómo funcionan, abra una ventana de símbolo del sistema, ejecute allí los siguientes comandos y lea con cuidado todas las páginas de ayuda que se muestran para cada comando.
-
echo /?
-
for /?
-
ping /?
-
rem /?
-
set /?
-
wmic /?
-
wmic path /?
Quiero escribir una simple pieza de código para obtener una buena "marca de tiempo" formateada.
Poner el tiempo en mis dos variables
Start
y
End
funciona bien.
También puedo imprimirlo como 0: 0: 0.
Quiero tener un cero a la izquierda si es menor que 10, pero aparentemente recibo un error que dice ''el parámetro 10 no se encuentra o está mal escrito''.
Descubrí que esta parece ser la variable a comparar, pero no pude solucionarlo.
¿Algunas ideas?
@ECHO OFF
REM Time Calculation
FOR /F "skip=1 tokens=1-6" %%A IN (''WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Second /Format:table ^| findstr /r "."'') DO (
set Day=%%A
set Hour=%%B
set Minute=%%C
set Second=%%D
)
set /a Start=%Day%*8640000+%Hour%*360000+%Minute%*6000+%Second%*100
@ECHO ON
ping 8.8.8.8 -n 11
@ECHO OFF
FOR /F "skip=1 tokens=1-6" %%A IN (''WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Second /Format:table ^| findstr /r "."'') DO (
set Day=%%A
set Hour=%%B
set Minute=%%C
set Second=%%D
)
set /a End=%Day%*8640000+%Hour%*360000+%Minute%*6000+%Second%*100
set /a Diff=%End%-%Start%
set /a Diff=(%Diff%)/100
set /a DiffSec=%Diff%%%60
set /a Diff=(%Diff%-%Diff%%%60)/60
set /a DiffMin=%Diff%%%60
set /a Diff=(%Diff%-%Diff%%%60)/60
set /a DiffHrs=%Diff%
ECHO Laufzeit Auftraege loeschen: %DiffHrs%:%DiffMin%:%DiffSec%
:: format with leading zeroes
if %DiffSec% LSS 10 (ECHO "LESS 10")else %DiffSec% LSS 1 (ECHO "LESS 1")
::if %DiffSec% LSS 10 (set DiffSec=0%DiffSec%)else [%DiffSec%] LSS 1 (set DiffSec=00)
::if %DiffMin% LSS 10 (set DiffMin=0%DiffMin%)else [%DiffMin%] LSS 1 (set DiffMin=00)
::if %DiffHrs% LSS 10 (set DiffHrs=0%DiffHrs%)else [%DiffHrs%] LSS 1 (set DiffHrs=00)
ECHO Laufzeit Auftraege loeschen: %DiffHrs%:%DiffMin%:%DiffSec%
if %DiffSec% LSS 10 (ECHO "LESS 10")else IF %DiffSec% LSS 1 (ECHO "LESS 1")
necesitas un
if
después de lo
else
.