¿El bucle for DOS de lote con FIND.exe está eliminando líneas en blanco?

Esta secuencia de comandos por lotes DOS está eliminando las líneas en blanco y no muestra las líneas en blanco en el archivo aunque estoy usando el comando TYPE.exe para convertir el archivo y asegurarme de que el archivo sea ASCII para que el comando FIND sea compatible con el archivo . ¿Alguien puede decirme cómo hacer que este guión incluya líneas en blanco?

@ECHO off FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE.exe "build.properties" ^| FIND.exe /V ""`) DO ( ECHO --%%A-- ) pause 

Ese es el comportamiento diseñado de FOR / F: nunca devuelve líneas en blanco. La solución alternativa es usar FIND o FINDSTR para anteponer la línea al número de línea. Si puede garantizar que ninguna línea comience con el delimitador del número de línea, simplemente configure el delimitador apropiado y conserve los tokens 1 * pero use solo el 2 token.

 ::preserve blank lines using FIND, assume no line starts with ] ::long lines are truncated for /f "tokens=1* delims=]" %%A in ('type "file.txt" ^| find /n /v ""') do echo %%B ::preserve blank lines using FINDSTR, assume no line starts with : ::long lines > 8191 bytes are lost for /f "tokens=1* delims=:" %%A in ('type "file.txt" ^| findstr /n "^"') do echo %%B ::FINDSTR variant that preserves long lines type "file.txt" > "file.txt.tmp" for /f "tokens=1* delims=:" %%A in ('findstr /n "^" "file.txt.tmp"') do echo %%B del "file.txt.tmp" 

Prefiero FINDSTR, es más confiable. Por ejemplo, FIND puede truncar líneas largas: FINDSTR no siempre y cuando lea directamente desde un archivo. FINDSTR deja caer líneas largas cuando lee de stdin a través de una tubería o redirección.

Si el archivo puede contener líneas que comiencen con el delimitador, entonces debe preservar toda la línea con el prefijo del número de línea, y luego usar buscar y reemplazar para eliminar el prefijo de línea. Probablemente desee una expansión retrasada cuando transfiera el %% A a una variable de entorno; de lo contrario, ¡cualquiera! será corrompido Pero luego, dentro del ciclo, necesita demorar la expansión para realizar la búsqueda y el reemplazo.

 ::preserve blank lines using FIND, even if a line may start with ] ::long lines are truncated for /f "delims=" %%A in ('type "file.txt" ^| find /n /v ""') do ( set "ln=%%A" setlocal enableDelayedExpansion set "ln=!ln:*]=!" echo(!ln! endlocal ) ::preserve blank lines using FINDSTR, even if a line may start with : ::long lines >8191 bytes are truncated for /f "delims=*" %%A in ('type "file.txt" ^| findstr /n "^"') do ( set "ln=%%A" setlocal enableDelayedExpansion set "ln=!ln:*:=!" echo(!ln! endlocal ) ::FINDSTR variant that preserves long lines type "file.txt" >"file.txt.tmp" for /f "delims=*" %%A in ('findstr /n "^" "file.txt.tmp"') do ( set "ln=%%A" setlocal enableDelayedExpansion set "ln=!ln:*:=!" echo(!ln! endlocal ) del "file.txt.tmp" 

Si no necesita preocuparse por convertir el archivo a ASCII, entonces es más eficiente soltar el conducto y dejar que FIND o FINDSTR abran el archivo especificado como un argumento o mediante una redirección.

Hay otro trabajo que evita por completo FOR / F durante el proceso de lectura. Parece extraño, pero es más eficiente. No hay restricciones con el uso de la expansión retrasada, pero desafortunadamente tiene otras limitaciones.

1) las líneas deben ser terminadas por (esto no será un problema si haces la conversión de archivo TYPE)

2) las líneas deben tener <= 1021 bytes de longitud (sin tener en cuenta )

3) cualquier rastro de caracteres de control se eliminan de cada línea.

4) debe leer de un archivo; no puede usar un tubo. Por lo tanto, en su caso necesitará usar un archivo temporal para realizar su conversión a ASCII.

 setlocal enableDelayedExpansion type "file.txt">"file.txt.tmp" for /f %%N in ('find /c /v "" ^<"file.txt.tmp"') do set cnt=%%N <"file.txt.tmp" ( for /l %%N in (1 1 %cnt%) do( set "ln=" set /p "ln=" echo(!ln! ) ) del "file.txt.tmp" 

Escribí un progtwig muy simple que puede servir como reemplazo para los comandos FIND y FINDSTR cuando se usan para este propósito. Mi progtwig se llama PIPE.COM y simplemente inserta un espacio en blanco en líneas vacías, por lo que todas las líneas pueden procesarse directamente con el comando FOR sin más ajustes (siempre que el espacio insertado no se preocupe). Aquí está:

 @ECHO off if not exist pipe.com call :DefinePipe FOR /F "USEBACKQ delims=" %%A IN (`pipe ^< "build.properties"`) DO ( ECHO(--%%A-- ) pause goto :EOF :DefinePipe setlocal DisableDelayedExpansion set pipe=´)€ì!Í!ŠÐŠà€Ä!€ü.t2€ü+u!:æu8²A€ê!´#€ì!Í!².€ê!´#€ì!Í!²+€ê!´#€ì!Í!Šò€Æ!´,€ì!Í!"Àu°´LÍ!ëÒ setlocal EnableDelayedExpansion echo !pipe!>pipe.com exit /B 

EDIT : Addendum como respuesta a un nuevo comentario

El código en: subrutina DefinePipe crea un progtwig de 88 bytes llamado pipe.com, que básicamente hace un proceso equivalente a este código de pseudo-Batch:

 set "space= " set line= :nextChar rem Read just ONE character set /PC char= if %char% neq %NewLine% ( rem Join new char to current line set line=%line%%char% ) else ( rem End of line detected if defined line ( rem Show current line echo %line% set line= ) else ( rem Empty line: change it by one space echo %space% ) ) goto nextChar 

De esta forma, las líneas vacías en el archivo de entrada se cambian por líneas con un espacio, por lo que el comando FOR / F ya no las omite. Esto funciona “siempre que el espacio insertado no se preocupe”, como dije en mi respuesta.

Tenga en cuenta que el progtwig pipe.com no funciona en versiones de 64 bits de Windows.

Antonio

Líneas de salida que incluyen líneas en blanco

Aquí hay un método que desarrollé para mi propio uso.

Guarde el código como un archivo por lotes, por ejemplo, SHOWALL.BAT y pase el archivo fuente como un parámetro de línea de comando.

La salida puede ser redirigida o canalizada.

 @echo off for /f "tokens=1,* delims=]" %%a in ('find /n /v "" ^< "%~1"') do echo.%%ba exit /b 

EJEMPLOS:

showall source.txt

showall source.txt > destination.txt

showall source.txt | ENCONTRAR "cadena"

Una rareza es la inclusión de ' ^ < ' (redirección) en lugar de simplemente hacer lo siguiente:

 for /f "tokens=1,* delims=]" %%a in ('find /n /v "" "%~1"') do echo.%%ba 

Al omitir la redirección, se genera una línea en blanco inicial.

Gracias a dbenham, esto funciona, aunque es ligeramente diferente de su sugerencia:

 ::preserve blank lines using FIND, no limitations for /f "USEBACKQ delims=" %%A in (`type "file.properties" ^| find /V /N ""`) do ( set "ln=%%A" setlocal enableDelayedExpansion set "ln=!ln:*]=!" echo(!ln! endlocal ) 

Como se menciona en esta respuesta a la pregunta anterior, no parece que las líneas se salten de manera predeterminada usando for /f en (al menos) Windows XP (Comunidad – Actualice esta respuesta probando los comandos de proceso por lotes a continuación en su versión y servicio paquete de Windows ).

EDITAR: Según el comentario de Jeb a continuación , parece que el comando ping , al menos en Windows XP , es
haciendo for /f produzca en lugar de líneas en blanco (si alguien sabe específicamente por qué,
agradezco si pudieran actualizar esta respuesta o comentario).

Como solución temporal, parece que el segundo token delimitado por defecto ( / %%b en el ejemplo)
regresa como en blank , lo que funcionó para mi situación de eliminar las líneas en blanco por medio de un “padre”
if condicionado al segundo token al comienzo de for /f , así:

  for /f "tokens=1,2*" %%a in ('ping -n 1 google.com') do ( if not "x%%b"=="x" ( {do things with non-blank lines} ) ) 

Usando el siguiente código:

 @echo off systeminfo | findstr /b /c:"OS Name" /c:"OS Version" echo.&echo. ping -n 1 google.com echo.&echo. for /f %%a in ('ping -n 1 google.com') do ( echo "%%a" ) echo.&echo.&echo --------------&echo.&echo. find /? echo.&echo. for /f %%a in ('find /?') do ( echo "%%a" ) echo.&echo. pause 

…. lo siguiente es lo que veo en Windows XP, Windows 7 y Windows 2008, siendo las únicas tres versiones y paquetes de servicios de Windows a los que tengo acceso inmediato:

Windows XP Pro SP3

Windows 7 Enterprise SP1

Windows Server 2008 R2 Enterprise SP1