Comment remplacer la même ligne dans la sortie de commande du fichier de commandes

13

Je veux écrire des informations d'état qui remplacent la dernière ligne lorsque je fais quelque chose.

Dans l'exemple de fichier bat suivant, je veux que le texte soit Step 2écrasé Step 1sur la même ligne dans la sortie de la commande.

echo off

echo Step 1
REM Do some stuff...

echo Step 2
REM do some other stuff...
admiration
la source

Réponses:

8

Ce script fera exactement ce que vous avez demandé:

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

J'ai trouvé cette réponse en regardant le code dans une bibliothèque de manipulation de caractères de script batch écrite par Dave Benham appelée CharLib .

Cette bibliothèque est capable de créer tous les personnages dans la plage 1..255.

Pour plus d'informations, voir le fil de discussion intitulé "Est-il possible de convertir un caractère à sa valeur ASCII?"

Edit 2017-4-26: Il semble que le code ci-dessus ne fonctionne plus . Je ne sais pas quand ce comportement aurait changé, mais il fonctionnait définitivement. Le CRpersonnage après le =maintenant est supprimé par la setcommande. Ah, cela semble être un changement dans la façon dont setfonctionne entre XP et les versions ultérieures de Windows. Voir l'excellente réponse dans la ligne Écraser dans le fichier de commandes Windows? (dupliquer) pour plus de détails et des exemples de code supplémentaires.

Une alternative consiste alors à mettre un caractère non blanc avant le !ASCII_13!et à le supprimer également, peut-être soit en insérant également un espace arrière (qui ne sera pas supprimé) suivi d'un espace ou en ajoutant des espaces à la fin du chaîne d'invite (qui n'est pas supprimée.)

Par exemple, comme ceci:

@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...
timfoden
la source
2
Pour moi, cela imprime simplement "Étape 1 Étape 2" au lieu d'avoir simplement "Étape 2" à l'écran.
galmok
@galmok Cela a commencé à m'arriver aussi, mais je suis sûr que cela n'a jamais été le cas (car j'ai un script qui fonctionnait parfaitement et qui récemment a changé pour le comportement que vous décrivez.) Il semble que la setcommande supprime maintenant tout Les caractères CR et LF (ainsi que les espaces) après le =. Essayez de mettre un caractère non blanc entre le =et le!ACSII_13!
timfoden
Il y a un moyen de faire tout cela ... Je suis en fait venu pour voir si quelqu'un d'autre l'avait remarqué, parce que je voulais voir s'ils avaient découvert jusqu'où cela allait. ... Puis-je rédiger une RÉPONSE en cas de débordement de pile? OU .. comme une question et y répondre immédiatement? Je suppose que je pourrais l'écrire sous forme de questions sur ce que vous pourriez en faire .. Je dois aller manger quelque chose mais je vais le mettre à jour avec un lien pour vous.
Brent Rittenhouse
Écrivez! ASCII_13! après l'étape 1 pour empêcher le décapage, vous devez donc coder à l'étape 2:set /p "=Step 2 " <NUL
Zimba
6

Pour répondre à la question:

@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

Production:

End

Fondamentalement, ce que le script fait, c'est d'écrire Step 1, puis remonte d'un endroit, écrase 1, et à la fin revient complètement et écrase Step 2avec End.

Je reviens en arrière avec le caractère ASCII spécial 8 qui est le retour arrière. Parce que je ne sais pas comment l'écrire en cmd, j'utilise la fonction: EVALUATE qui exécute la fonction VBS Chr () et place le caractère de retour arrière dans la variable result. Si quelqu'un connaît un meilleur moyen, veuillez en informer.

Davor Josipovic
la source
1
Dans PowerShell, vous pouvez également stocker $host.ui.RawUI.CursorPositiondans une variable et la restaurer plus tard pour que le curseur revienne à l'endroit où vous vous trouviez et écrase votre sortie. Seulement une option pour PowerShell, mais peut être un peu plus propre que vos trucs 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

EXPLICATION:

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

cela mettra le caractère de retour arrière dans la variable BSPACE. Maintenant, pour voir le résultat, tapez:

echo ab%BSPACE%c

production: ac

vous pouvez utiliser cette variable BSPACE plusieurs fois pour supprimer plusieurs caractères.

Maintenant, si vous souhaitez définir un retour chariot dans une variable, utilisez

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

pour voir le résultat, tapez: setlocal EnableDelayedExpansion & echo asfasdhlfashflkashflksa!CR!***

la sortie sera: ***asfasdhlfashflkashflksa

La réponse de @ davour ci-dessus est également belle mais la réponse de @ timfoden n'a pas fonctionné pour moi.

Sourav Ghosh
la source
La réponse de @ timfoden n'a pas fonctionné car! CR! devrait aller à la fin de l'étape précédente. De plus, au lieu de tous ces% BSPACE% s, vous pourriez aussi! CR! et remplis d'espaces:set /p "=.!CR!End. " <NUL&echo:
Zimba
3

Tu ne peux pas. Habituellement, vous pouvez réaliser ce genre de chose en incluant un caractère de retour chariot (0x0D) dans le fichier qui replacera le curseur dans la première colonne de la même ligne. Mais dans ce cas, cela ne fonctionne pas; le CR est mangé en silence.

De plus, obtenir le CR là-dedans est un peu délicat et au moins ici impliqué un éditeur de texte. Je vous suggère d'écrire un petit programme utilitaire qui fera cela pour vous, ce n'est en fait pas très difficile. Le petit programme C suivant peut suffire (si vous n'avez pas besoin d'Unicode):

#include <stdio.h>

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

Il ne fait rien de plus que d'imprimer un caractère CR, puis le texte que vous spécifiez comme premier argument. Utilisation comme suit:

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

La dernière ligne est l'appel à ce programme. La deuxième ligne est l'idiome de lot normal pour l'impression de texte sans rupture de ligne de fin (ce qui est important dans ce cas car sinon vous ne pourriez pas écraser la ligne). Vous pouvez tout aussi bien utiliser le programme ci-dessus à cet endroit.

Une manière légèrement hacky, mais la seule où vous pouvez être sûr où vous vous retrouvez, serait d'utiliser clsavant votre sortie pas à pas. Scintillera mais de cette façon, vous écrivez toujours en haut à gauche. Et clobber tout ce qui était visible dans la console (c'est pourquoi je ne le recommanderais pas); la plupart des utilisateurs n'aiment pas trop ça.

Joey
la source
OK, j'avais un soupçon qu'il n'était pas possible de faire avec une ligne de commande propre. Si je veux faire un utilitaire faire cela, je ferais aussi bien de mettre le tout dans un utilitaire. Ce que je voulais vraiment, c'était juste un compte à rebours visible qui attendait 5 secondes, comptant chaque seconde jusqu'à la fin.
admiration
4
awe: Si vous êtes sur Vista ou version ultérieure, alors timeout 5cela fonctionnera.
Joey
Génial! Merci! timeout 5 fonctionne!
admiration
4
J'aurais dû poster mon vrai problème la première fois ...
awe
Bien sûr vous pouvez; ajoutez simplement le retour chariot après l'étape 1! De plus, voici du code pour obtenir le retour chariot sans impliquer l'éditeur de texte:for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
Zimba
1

Obtenez le caractère de nouvelle ligne, écrivez l'étape suivante, revenez au début de la ligne, écrivez la ligne suivante:

@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.
Zimba
la source
Cela ne fonctionnera que si Step 1 Step 2 Step 3tous sont de la même longueur. Sinon, le texte du premier set /preste. Je ne sais pas comment résoudre ce problème.
Ste
Ce problème peut être résolu en utilisant des espaces supplémentaires dans l'invite suivante. pour couvrir tous les caractères précédents. Exemple set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NUL par opposition à set /p "=Step 2!Newline!" <NUL. Échangez SPACEcontre le personnage.
Ste
Si les lignes précédentes sont plus longues, ajoutez des espaces pour effacer les caractères supplémentaires, ou un retour arrière de la fin de la ligne au début, ou simplement un retour arrière pour les caractères supplémentaires.
Zimba
0

Vous auriez besoin d'une bibliothèque de curseurs d'écran comme cursesou ncurses, mais je ne connais pas trop leur utilisation. Les deux bibliothèques ont été développées pour les systèmes Unix, mais vous pouvez les trouver pour Windows (dans l' environnement Cygwin ou GnuWin32 ).

Je ne connais aucun moyen facile d'y accéder dans un fichier batch de style DOS. Vous feriez peut-être mieux de programmer dans un langage compilé. Jetez un œil au Ncurses HOWTO pour avoir une meilleure idée de son utilité.

Quack Quichotte
la source
les malédictions sont à peu près uniquement destinées aux terminaux et aux émulateurs de terminaux. Ils ne correspondent pas vraiment à l'API de la console native de Windows.
Joey
PAS besoin de bibliothèques externes; fonctionne très bien avec les outils CMD.
Zimba
0

Solution 1

Avec Notepad ++, il est possible d'insérer le Backspace ←caractère (ASCII 0x08) directement, en utilisant son panneau d'insertion de codes ASCII (Édition> Panneau de caractères).

Ma solution consiste à insérer le [BS]caractère directement puis, comme les autres solutions publiées ici, à l'utiliser plusieurs fois pour supprimer les caractères précédents:

Code

@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

Capture d'écran du Bloc-notes ++

Écrasement par lots de Windows


Production

Sortie CMD


Solution 2

Une autre possibilité consiste à utiliser cecho (commande echo avec prise en charge des couleurs) pour insérer un Carriage Return ↵comme caractère unicode (U + 000D):

Code

@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.exetourne beaucoup plus vite sur ma machine que cecho.exe.

andronoïde
la source