Come sovrascrivere la stessa riga nell'output del comando dal file batch


13

Voglio scrivere alcune informazioni sullo stato che sostituiscono l'ultima riga quando faccio qualcosa.

Nel seguente esempio di file bat, voglio che il testo Step 2venga sovrascritto Step 1sulla stessa riga nell'output del comando.

echo off

echo Step 1
REM Do some stuff...

echo Step 2
REM do some other stuff...

Risposte:


8

Questo script farà esattamente quello che hai chiesto:

@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...

Ho trovato questa risposta guardando il codice in una libreria di manipolazione dei caratteri di script batch scritta da Dave Benham chiamata CharLib .

Questa libreria è in grado di creare tutti i caratteri nell'intervallo 1..255.

Per maggiori informazioni vedi il thread intitolato "È possibile convertire un carattere nel suo valore ASCII?"

Modifica 2017-4-26: Sembra che il codice sopra non funzioni più . Non sono sicuro di quando questo comportamento sarebbe cambiato, ma sicuramente funzionava. Il CRpersonaggio dopo =ora viene rimosso dal setcomando. Ah, sembra essere un cambiamento nel modo in cui setfunziona tra XP e le versioni successive di Windows. Vedi la risposta eccellente nella riga Sovrascrivi nel file batch di Windows? (duplicato) per maggiori dettagli ed esempi di codice extra.

Un'alternativa quindi è quella di mettere un carattere non bianco prima del !ASCII_13!e di provvedere alla cancellazione anche di esso, magari inserendo anche uno spazio (che non viene rimosso) seguito da uno spazio o aggiungendo spazi alla fine del stringa di prompt (che non sono rimosse).

Ad esempio in questo modo:

@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
Per me, questo stampa solo "Step 1Step 2" invece di avere solo "Step 2" sullo schermo.
Galmok,

@galmok Anche questo ha cominciato a succedere anche a me, ma sono sicuro che non lo era mai stato (dato che ho uno script che funzionava perfettamente messo recentemente, è cambiato nel comportamento che descrivi). Sembra che il setcomando ora spoglia qualsiasi Caratteri CR e LF (nonché spazi) dopo il =. Prova a mettere un carattere non bianco tra il =e il!ACSII_13!
timfoden il

C'è un modo per fare tutto questo ... In realtà sono venuto a vedere se qualcuno se ne fosse accorto, perché volevo vedere se avessero scoperto quanto lontano fosse andato. ... Posso scrivere una RISPOSTA sullo overflow dello stack? O .. come una domanda e rispondere immediatamente? Suppongo che potrei scriverlo in forma di domanda su cosa potresti farci .. Devo andare a mangiare qualcosa ma lo aggiornerò con un link per te.
Brent Rittenhouse,

Scrivi! ASCII_13! dopo il passaggio 1 per evitare lo stripping, quindi nel passaggio 2 si set /p "=Step 2 " <NUL
codificherà

6

Per rispondere alla domanda:

@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

Produzione:

End

In sostanza, cosa fa lo script, è scrive Step 1, poi torna un unico luogo, sovrascrittura 1, e alla fine va completamente indietro e sovrascrive Step 2con End.

Questo a ritroso lo faccio con lo speciale carattere ASCII 8 che è backspace. Poiché non so come scriverlo in cmd, utilizzo la funzione: EVALUATE che esegue la funzione VBS Chr () e inserisce il carattere backspace nella variabile result. Se qualcuno conosce un modo migliore, si prega di avvisare.


1
In PowerShell, puoi anche archiviare $host.ui.RawUI.CursorPositionuna variabile e ripristinarla in un secondo momento per far tornare il cursore nel punto in cui ti trovavi e sovrascrivere l'output. Solo un'opzione per PowerShell, ma potrebbe essere un po 'più pulita delle tue cose 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

SPIEGAZIONE:

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

questo imposterà il carattere backspace nella variabile BSPACE. Ora per vedere il risultato, digitare:

echo ab%BSPACE%c

produzione: ac

puoi utilizzare questa variabile BSPACE più di una volta per eliminare più caratteri.

Ora, se si desidera impostare un ritorno a capo in una variabile, utilizzare

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

per vedere il risultato, digitare: setlocal EnableDelayedExpansion & echo asfasdhlfashflkashflksa!CR!***

l'output sarà: ***asfasdhlfashflkashflksa

Anche la risposta di @ davour sopra è bella ma la risposta di @ timfoden non ha funzionato per me.


La risposta di @ timfoden non ha funzionato perché! CR! dovrebbe andare alla fine del passaggio precedente. Inoltre, invece di tutti quei% BSPACE% s, potresti anche! CR! e riempi di spazi bianchi:set /p "=.!CR!End. " <NUL&echo:
Zimba,

3

Non puoi. Di solito è possibile ottenere questo tipo di cose includendo un carattere di ritorno a capo (0x0D) nel file che riporterà il cursore sulla prima colonna della stessa riga. Ma in questo caso non funziona; il CR viene mangiato in silenzio.

Inoltre, ottenere il CR è un po 'complicato e almeno qui coinvolge un editor di testo. Ti suggerirei di scrivere un piccolo programma di utilità che farà questo per te, in realtà non è molto difficile. Il seguente piccolo programma C potrebbe essere sufficiente (se non è necessario Unicode):

#include <stdio.h>

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

Non fa altro che stampare un carattere CR e quindi il testo specificato come primo argomento. Utilizzo come segue:

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

L'ultima linea è la chiamata a quel programma. La seconda riga è il normale linguaggio batch per la stampa di testo senza un'interruzione di riga finale (che è importante in questo caso perché altrimenti non è possibile sovrascrivere la riga). Tuttavia, puoi anche usare il programma sopra e anche in quel posto.

Un modo leggermente confuso, ma l'unico in cui puoi essere sicuro di dove finirai, sarebbe quello di usarlo clsprima del tuo step output. Sfarfallerà, ma in questo modo scrivi sempre in alto a sinistra. E blocca tutto ciò che era visibile nella console (motivo per cui non lo consiglierei); alla maggior parte degli utenti non piace molto.


OK, avevo il sospetto che non fosse possibile farlo con una riga di comando pulita. Se voglio fare un programma di utilità fare questo, potrei anche mettere tutto in un programma di utilità. Quello che volevo davvero era solo un conto alla rovescia visibile che aspettasse 5 secondi, il conto alla rovescia ogni secondo fino al termine.
timore re

4
soggezione: se sei su Vista o versioni successive, allora timeout 5funzionerà.
Joey,

Grande! grazie! timeout 5 funziona!
timore re

4
Avrei dovuto postato il mio vero problema per la prima volta ...
awe

Certo che puoi; aggiungi il ritorno a capo dopo il passaggio 1! Inoltre, ecco un po 'di codice per ottenere il ritorno a capo senza coinvolgere l'editor di testo:for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
Zimba,

1

Ottieni il carattere di nuova riga, scrivi il passaggio successivo, torna all'inizio della riga, scrivi la riga successiva:

@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.

Funzionerà solo se Step 1 Step 2 Step 3hanno tutti la stessa lunghezza. Altrimenti set /primane il testo del primo . Non sono sicuro di come risolvere questo problema.
Ste

Tale problema può essere risolto utilizzando caratteri di spazi aggiuntivi nel prompt successivo. per coprire tutti i personaggi precedenti. Esempio set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NUL al contrario di set /p "=Step 2!Newline!" <NUL. Scambia SPACEper il personaggio.
Ste

Se le righe precedenti sono più lunghe, aggiungi gli spazi per cancellare i caratteri extra o il backspace dalla fine della riga all'inizio o semplicemente il backspace ai caratteri extra.
Zimba,

0

Avresti bisogno di una libreria di cursori dello schermo come curseso ncurses, ma non ho troppa familiarità con il loro uso. Entrambe le librerie sono state sviluppate per i sistemi Unix, ma puoi trovarle per Windows (nell'ambiente Cygwin o GnuWin32 ).

Non conosco alcun modo semplice per accedervi in ​​un file batch in stile DOS. Potrebbe essere meglio programmare in un linguaggio compilato. Dai un'occhiata al Ncurses HOWTO per avere una migliore idea se sarà utile.


le maledizioni sono praticamente solo per terminali ed emulatori di terminali. Non si associano realmente all'API della console nativa di Windows.
Joey,

Nessuna necessità di librerie esterne; funziona bene con gli strumenti CMD.
Zimba,

0

Soluzione 1

Con Notepad ++ è possibile inserire direttamente il Backspace ←carattere (ASCII 0x08), usando il pannello Inserimento codici ASCII (Modifica> Pannello caratteri).

La mia soluzione è quella di inserire il [BS]carattere direttamente e quindi, come altre soluzioni pubblicate qui, utilizzarlo più volte per eliminare i caratteri precedenti:

Codice

@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

Schermata Notepad ++

Sovrascrittura batch di Windows


Produzione

Uscita CMD


Soluzione 2

Un'altra possibilità è usare cecho (comando echo con supporto colori) per inserire un Carriage Return ↵carattere unicode (U + 000D):

Codice

@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.exefunziona molto più velocemente sulla mia macchina rispetto a cecho.exe.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.