Cómo sobrescribir la misma línea en la salida del comando del archivo por lotes


13

Quiero escribir información de estado que reemplace la última línea cuando hago algo.

En el siguiente ejemplo del archivo bat, quiero que el texto se Step 2sobrescriba Step 1en la misma línea en la salida del comando.

echo off

echo Step 1
REM Do some stuff...

echo Step 2
REM do some other stuff...

Respuestas:


8

Este script hará exactamente lo que pediste:

@echo off

setlocal enableextensions enabledelayedexpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "ASCII_13=%%a"

set /p "=Step 1" <NUL
REM Do some stuff...

set /p "=!ASCII_13!Step 2" <NUL
REM do some other stuff...

Encontré esta respuesta mirando el código en una biblioteca de manipulación de caracteres de secuencia de comandos por lotes escrita por Dave Benham llamada CharLib .

Esta biblioteca puede crear todos los caracteres en el rango 1..255.

Para obtener más información, consulte el hilo titulado "¿Es posible convertir un carácter a su valor ASCII?"

Editar 2017-4-26: Parece que el código anterior ya no funciona . No estoy seguro de cuándo habría cambiado este comportamiento, pero definitivamente solía funcionar. El CRpersonaje después del =ahora es eliminado por el setcomando. Ah, parece ser un cambio en la forma en que setfunciona entre XP y versiones posteriores de Windows. ¿Ves la excelente respuesta en Sobrescribir línea en el archivo por lotes de Windows? (duplicado) para más detalles y ejemplos de código extra.

Entonces, una alternativa es colocar un carácter que no sea un espacio en blanco antes !ASCII_13!y organizarlo para que también se borre, quizás insertando también un espacio de retroceso (que no se elimine) seguido de un espacio o agregando espacios al final del cadena de solicitud (que no se eliminan)

Por ejemplo, así:

@echo off

setlocal enableextensions enabledelayedexpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "ASCII_13=%%a"

set /p "=Step 1" <NUL
REM Do some stuff...

set /p "=x!ASCII_13!Step 2 " <NUL
REM do some other stuff...

2
Para mí, esto solo imprime "Paso 1 Paso 2" en lugar de tener solo "Paso 2" en la pantalla.
galmok

@galmok Esto también ha comenzado a sucederme a mí, pero estoy seguro de que nunca solía hacerlo (ya que tengo un script que solía funcionar perfectamente puesto recientemente ha cambiado al comportamiento que usted describe). Parece que el setcomando ahora elimina cualquier Caracteres CR y LF (así como espacios) después de =. Trate de poner un personaje no está en blanco entre el =y el!ACSII_13!
timfoden

Hay una manera de hacer todo esto ... De hecho, vine a ver si alguien más se ha dado cuenta, porque quería ver si habían descubierto hasta dónde llegó. ... ¿Puedo escribir una RESPUESTA en el desbordamiento de la pila? O .. como una pregunta e inmediatamente la respondes? Supongo que podría escribirlo en forma de pregunta sobre lo que podría hacer con él. Tengo que ir a comer algo, pero lo actualizaré con un enlace para usted.
Brent Rittenhouse

Escribe! ASCII_13! después del paso 1 para evitar la eliminación, por lo que en el paso 2 codificaría:set /p "=Step 2 " <NUL
Zimba

6

Para responder la pregunta:

@echo off
CALL :EVALUATE "chr(8)"
SET backspace=%result%
<nul set /p =Step 1
:: DO SOME STUFF....
<nul set /p =%backspace%
<nul set /p =2
:: DO SOME OTHER STUFF....
<nul set /p =%backspace%%backspace%%backspace%%backspace%%backspace%%backspace%
<nul set /p =End   
GOTO:EOF



:EVALUATE           -- evaluate with VBS and return to result variable
::                  -- %~1: VBS string to evaluate
:: extra info: http://groups.google.com/group/alt.msdos.batch.nt/browse_thread/thread/9092aad97cd0f917

@IF [%1]==[] ECHO Input argument missing & GOTO :EOF 

@ECHO wsh.echo "result="^&eval("%~1") > %temp%\evaluate_tmp_67354.vbs 
@FOR /f "delims=" %%a IN ('cscript //nologo %temp%\evaluate_tmp_67354.vbs') do @SET "%%a" 
@DEL %temp%\evaluate_tmp_67354.vbs
::ECHO %result%
@GOTO:EOF

Salida:

End

Básicamente, lo que hace el guión es escribir Step 1, luego retrocede un lugar, sobrescribe 1y al final retrocede completamente y sobrescribe Step 2con End.

Esto lo vuelvo a hacer con el carácter especial ASCII 8 que es retroceso. Como no sé cómo escribirlo en cmd, utilizo la función: EVALUATE que ejecuta la función VBS Chr () y coloca el carácter de retroceso en la variable result. Si alguien conoce una mejor manera, por favor avise.


1
En PowerShell, también puede almacenar $host.ui.RawUI.CursorPositionen una variable y restaurarla más tarde para que el cursor salte a donde estaba y sobrescriba su salida. Solo es una opción para PowerShell, pero puede ser un poco más limpio que sus cosas de VBS :-)
mihi

4
@echo off
for /F "tokens=1 delims=# " %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do set "BSPACE=%%a"
<nul set /p =Step 1
ping 127.0.0.1 >nul
<nul set /p =%BSPACE%
<nul set /p =2
ping 127.0.0.1 >nul
<nul set /p =%BSPACE%
<nul set /p =3
ping 127.0.0.1 >nul
<nul set /p =%BSPACE%%BSPACE%%BSPACE%%BSPACE%%BSPACE%%BSPACE%
<nul set /p =End.  
pause

EXPLICACIÓN:

for /F "tokens=1 delims=# " %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do set "BSPACE=%%a"

esto establecerá el carácter de retroceso en la variable BSPACE. Ahora para ver el resultado, escriba:

echo ab%BSPACE%c

salida: ac

Puede usar esta variable BSPACE más de una vez para eliminar varios caracteres.

Ahora, si desea establecer un retorno de carro en una variable, use

for /F "usebackq" %%a in (copia / Z "% ~ dpf0" nul) DO (set "cr=%%a")

para ver el resultado, escriba: setlocal EnableDelayedExpansion & echo asfasdhlfashflkashflksa!CR!***

la salida será: ***asfasdhlfashflkashflksa

La respuesta de @ davour anterior también es hermosa, pero la respuesta de @ timfoden no funcionó para mí.


La respuesta de @ timfoden no funcionó porque! CR! debe ir al final del paso anterior. Además, en lugar de todos esos% BSPACE% s, ¡también podrías! CR! y llenar con espacios en blanco:set /p "=.!CR!End. " <NUL&echo:
Zimba

3

No puedes Por lo general, puede lograr este tipo de cosas al incluir un carácter de retorno de carro (0x0D) en el archivo que colocará el cursor nuevamente en la primera columna de la misma línea. Pero en este caso no funciona; El CR se come en silencio.

Además, introducir el CR allí es un poco complicado y al menos aquí involucra un editor de texto. Te sugiero que escribas un pequeño programa de utilidad que haga esto por ti, en realidad no es muy difícil. El siguiente pequeño programa en C podría ser suficiente (si no necesita Unicode):

#include <stdio.h>

int main(int argc, char* argv[]) {
  if (argc < 2) return 1;
  printf("\r%s", argv[1]);
}

No hace más que imprimir un carácter CR y luego el texto que especifique como primer argumento. Uso de la siguiente manera:

@echo off
<nul set /P X=Step 1
pause>nul 2>nul
over.exe "Step 2"

La última línea es la llamada a ese programa. La segunda línea es el lenguaje de lote normal para imprimir texto sin un salto de línea final (lo cual es importante en este caso porque de lo contrario no podría sobrescribir la línea). Sin embargo, también podría usar el programa anterior en ese lugar.

Una manera un poco hacky, pero la única en la que puede estar seguro de dónde terminará, sería usarla clsantes de la salida de su paso. Parpadeará, pero de esa manera siempre escribes en la esquina superior izquierda. Y apunte todo lo que estaba visible en la consola (por eso no lo recomendaría); A la mayoría de los usuarios no les gusta demasiado.


OK, sospechaba que no era posible hacerlo con una línea de comando limpia. Si quiero hacer que una utilidad haga esto, también podría poner todo en una utilidad. Lo que realmente quería era solo una cuenta regresiva visible que esperara 5 segundos, contando cada segundo hasta que terminara.
asombro

44
temor: si está en Vista o posterior, entonces timeout 5funcionará.
Joey

¡Excelente! ¡gracias! tiempo de espera 5 funciona!
asombro

44
Debería haber publicado mi problema real la primera vez ...
asombro

Por supuesto que puede; ¡simplemente agregue el retorno de carro después del paso 1! Además, aquí hay un código para obtener el retorno de carro sin involucrar al editor de texto:for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
Zimba

1

Obtenga el carácter de nueva línea, escriba el siguiente paso, regrese al inicio de la línea, escriba la siguiente línea:

@echo off
cls
setlocal enabledelayedexpansion
echo Here's how it's done:

for /f %%a in ('copy /Z "%~f0" nul') do set "Newline=%%a"
set /p "=Step 1!Newline!" <NUL
REM Do some stuff...
ping -n 2 localhost > nul
set /p "=Step 2!Newline!" <NUL
ping -n 2 localhost > nul
set /p "=Step 3 " <NUL
REM do some other stuff...
ping -n 2 localhost > nul
echo:
echo Done.

Esto solo funcionará si Step 1 Step 2 Step 3todos tienen la misma longitud. Si no, set /pqueda el texto del primero . No estoy seguro de como arreglar esto.
Ste

Ese problema se puede solucionar mediante el uso de caracteres de espacio en blanco adicionales en el siguiente mensaje. para cubrir cualquier personaje anterior. Ejemplo set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NUL en lugar de set /p "=Step 2!Newline!" <NUL. Intercambio SPACEpor el personaje.
Ste

Si las líneas anteriores son más largas, agregue espacios para dejar en blanco caracteres adicionales, o retroceda desde el final de la línea hasta el principio, o simplemente retroceda a los caracteres adicionales.
Zimba

0

Necesitaría una biblioteca de cursor de pantalla como curseso ncurses, pero no estoy demasiado familiarizado con su uso. Ambas bibliotecas se desarrollaron para sistemas Unix, pero puede encontrarlas para Windows (en el entorno Cygwin o GnuWin32 ).

No conozco ninguna forma fácil de acceder a ellos en un archivo por lotes de estilo DOS. Puede que sea mejor programar en un lenguaje compilado. Eche un vistazo al CÓMO de Ncurses para tener una mejor idea de si será útil.


las maldiciones son prácticamente solo para terminales y emuladores de terminal. Realmente no se asignan a la API de consola nativa de Windows.
Joey

NO necesita bibliotecas externas; funciona bien con herramientas CMD.
Zimba

0

Solución 1

Con Notepad ++ es posible insertar el Backspace ←carácter (ASCII 0x08) directamente, utilizando su Panel de inserción de códigos ASCII (Edición> Panel de caracteres).

Mi solución es insertar el [BS]carácter directamente y luego, como otras soluciones publicadas aquí, usarlo varias veces para eliminar caracteres anteriores:

Código

@ECHO OFF

SET "BACKSPACE_x7=[BS][BS][BS][BS][BS][BS][BS]"

SET /P "DUMMY_VAR=Step 1" < NUL
REM Do some stuff...

SET /P "DUMMY_VAR=%BACKSPACE_x7%Step 2" < NUL
REM Do some other stuff...

GOTO :EOF

Notepad ++ captura de pantalla

Sobrescritura por lotes de Windows


Salida

Salida CMD


Solución 2

Otra posibilidad es usar cecho (comando echo con soporte de colores) para insertar un Carriage Return ↵carácter unicode (U + 000D):

Código

@ECHO OFF

SET CARRIAGE_RETURN={\u000D}

cecho Step 1
REM Do some stuff...

cecho %CARRIAGE_RETURN%Step 2
REM Do some other stuff...

GOTO :EOF

NB: cecho_x64.exefunciona significativamente más rápido en mi máquina que cecho.exe.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.