Как перезаписать одну и ту же строку в выводе команды из командного файла
Я хочу написать некоторую информацию о состоянии, которая заменяет последнюю строку, когда я что-то делаю.
В следующем примере файл bat, я хочу текст Step 2
перезаписать Step 1
на той же строке в выводе команды.
echo off
echo Step 1
REM Do some stuff...
echo Step 2
REM do some other stuff...
8 ответов
Этот скрипт будет делать именно то, что вы просили:
@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...
Я нашел этот ответ, посмотрев код в библиотеке манипуляций с символами пакетного сценария, написанной Дэйвом Бенхэмом под названием CharLib.
Эта библиотека может создавать все символы в диапазоне 1..255.
Для получения дополнительной информации см. Тему "Можно ли преобразовать символ в его значение ASCII?"
Изменить 2017-4-26: Похоже, что приведенный выше код больше не работает. Я не уверен, когда это поведение изменилось бы, но оно определенно работало. CR
персонаж после =
теперь раздевается set
команда. Ах, похоже, это изменение в set
работает между XP и более поздними версиями Windows. Смотрите отличный ответ в строке перезаписи в командном файле Windows? (дубликаты) для более подробной информации и дополнительных примеров кода.
Альтернатива - поставить непробельный символ перед !ASCII_13!
и сделайте так, чтобы он тоже был удален, возможно, либо вставив символ возврата (который не удаляется) с последующим пробелом, либо добавив пробелы в конец строки приглашения (которые не были удалены).
Например, вот так:
@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...
Чтобы ответить на вопрос:
@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
Выход:
End
В основном то, что делает скрипт, это пишет Step 1
, затем возвращается на одно место, перезаписывает 1
и в конце полностью возвращается назад и перезаписывает Step 2
с End
,
Это возвращение я делаю со специальным символом ASCII 8, который является backspace. Поскольку я не знаю, как написать это в cmd, я использую функцию:EVALUATE, которая запускает функцию VBS Chr() и помещает символ возврата в переменную result
, Если кто-то знает лучший способ, пожалуйста, сообщите.
@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
ОБЪЯСНЕНИЕ:
for /F "tokens=1 delims=# " %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do set "BSPACE=%%a"
это установит символ возврата в переменную BSPACE. Теперь, чтобы увидеть результат, введите:
echo ab%BSPACE%c
выход:ac
Вы можете использовать эту переменную BSPACE более одного раза, чтобы удалить несколько символов.
Теперь, если вы хотите установить возврат каретки в переменной, используйте
for /F "usebackq" %%a in (
copy /Z "%~dpf0" nul) DO (set "cr=%%a")
чтобы увидеть результат, наберите:setlocal EnableDelayedExpansion
& echo asfasdhlfashflkashflksa!CR!***
вывод будет: ***asfasdhlfashflkashflksa
Ответ @davour выше также красив, но ответ @timfoden мне не помог.
Ты не можешь. Обычно этого можно добиться, добавив в файл символ возврата каретки (0x0D), который вернет курсор к первому столбцу в той же строке. Но в этом случае это не работает; ЧР просто молча едят.
Кроме того, получить CR там довольно сложно и, по крайней мере, здесь задействован текстовый редактор. Я бы посоветовал вам написать небольшую утилиту, которая сделает это за вас, на самом деле это не очень сложно. Может пригодиться следующая маленькая программа на C (если вам не нужен Unicode):
#include <stdio.h>
int main(int argc, char* argv[]) {
if (argc < 2) return 1;
printf("\r%s", argv[1]);
}
Он не делает ничего, кроме печати символа CR, а затем текста, который вы указываете в качестве первого аргумента. Использование следующим образом:
@echo off
<nul set /P X=Step 1
pause>nul 2>nul
over.exe "Step 2"
Последняя строка - это вызов этой программы. Вторая строка - это обычная идиома для печати текста без разрывов задней строки (что важно в этом случае, потому что в противном случае вы не сможете перезаписать строку). Вы можете также использовать вышеуказанную программу в этом месте.
Слегка хакерский способ, но единственным, где вы можете быть уверены, где вы окажетесь, будет использование cls
до вашего шага вывода. Будет мерцать, но вы всегда будете писать в верхнем левом углу. И затирайте все, что было видно в консоли (поэтому я бы не рекомендовал это); большинству пользователей это не нравится.
Получить символ новой строки, написать следующий шаг, вернуться к началу строки, написать следующую строку:
@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.
Вам понадобится библиотека экранных курсоров, как curses
или же ncurses
, но я не слишком знаком с их использованием. Обе библиотеки были разработаны для систем Unix, но вы можете найти их для Windows (в среде Cygwin или GnuWin32).
Я не знаю ни одного простого способа получить к ним доступ в пакетном файле в стиле DOS. Возможно, вам лучше программировать на скомпилированном языке. Взгляните на Ncurses HOWTO, чтобы лучше понять, будет ли это полезно.
Пользователи Windows 10 получают удовольствие от escape-последовательностей виртуального терминала. Однако они требуют некоторого изучения, и в отличие от большинства команд Windows, для них нет информации об использовании, доступной из командной строки. Удалить строки или даже несколько символов из текущей позиции курсора довольно просто. Однако при использовании нескольких кодов VT в комбинации скажем: скрыть курсор, сместить его положение, изменить цвет переднего/заднего фона и удалить несколько ячеек из текущей строки, используемые последовательности могут быстро превратиться в почти нечитаемую командную строку, которую трудно поддерживать.
Однако последовательности виртуального терминала предоставляют средства для точного управления свойствами отображения и улучшения вывода, и их стоит использовать.
Чтобы упростить использование последовательностей виртуального терминала и облегчить обслуживание кода, я создал приведенный ниже пакетный макрос для обработки нескольких аспектов вывода курсора в командной строке Windows 10, дополненный файлом справки, который поможет новым разработчикам пакетных сценариев узнать, что можно сделать. сделано с помощью виртуальных терминальных последовательностей.
Поддерживает и показывает примеры:
- Позиционирование курсора
- Абсолютный
- Относительно последней позиции курсора; влево вправо на n столбцов; вверх вниз на n строк
- Комбинации относительного и абсолютного положения.
- Показать/скрыть курсор
- Свойства графики курсора [ Цвет ; Передний план и фон]
- Многоцветный вывод в одну строку
- Легко объединяйте несколько графических последовательностей VT.
- Очистка всего текста в строке с заданной позиции.
- Удаление ряда символов справа от курсора в текущей строке.
- При необходимости сохраните положение курсора во время расширения как независимые значения Y и X.
- Переключение между экранными буферами.
Примечание:
Ниже последнего примера использования я включил командную строку, в которой используются коды VT для достижения того же результата, что и в этом примере, чтобы проиллюстрировать разницу в читаемости при использовании нескольких последовательностей терминала в одном и том же выводе курсора.
ПРИМЕЧАНИЯ По изменению буферов:
Позиция курсора привязана к активному буферу; Он недоступен при переключении на альтернативный буфер.
При возврате к основному буферу:
позиция курсора, первоначально занятая в основном буфере, восстанавливается, а содержимое альтернативного буфера удаляется.
Этот макрос завершает свое выполнение за 1/100 секунды — это с максимальным количеством аргументов и переключателей (на самом медленном из моих компьютеров с тактовой частотой 1,6 ГГц). В примерах между каждым расширением применяется задержка, чтобы дать время наблюдать за изменениями выходных данных.
::: Cout cursor Macro. Author: T3RRY ::: Filename: Cout.bat
::: OS requirement: Windows 10
::: Purpose: Facilitate advanced console display output with the easy use of Virtual terminal codes
::: Uses a macro function to effect display without users needing to memorise or learn specific
::: virtual terminal sequences.
::: Enables output of text in 255 bit color at absolute or relative Y;X positions.
::: Allows cursor to be hidden or shown during and after text output. See help for more info.
@Echo off & Setlocal EnableExtensions
============================================== :# Usage
If not "%~1" == "" Echo/%~1.|findstr /LIC:"/?" > nul && (
Cls & Mode 1000,50 & Color 30
If "%~2" == "DE" ( Color 04 & Echo/ --- Delayed expansion detected^^^! Must not be enabled prior to calling %~n0 ---&( Echo/n|choice /n /C:o 2> nul ))
If not Exist "%TEMP%\%~n0helpfile.~tmp" (For /F "Delims=" %%G in ('Type "%~f0"^| Findstr.exe /BLIC:":::" 2^> nul ')Do (
For /F "Tokens=2* Delims=[]" %%v in ("%%G")Do Echo(^|%%v^|
))>"%TEMP%\%~n0helpfile.~tmp"
Type "%TEMP%\%~n0helpfile.~tmp" | More
timeout /T 60 > nul
Color 07
If "%~2" == "DE" (Exit)Else Exit /B 0
)
If "!![" == "[" Call "%~f0" "/?" "DE"
:::[=====================================================================================================================]
:::[ cout /? ]
:::[ %COUT% Cursor output macro. ]
:::[ * Valid Args for COUT: {/Y:Argvalue} {/X:Argvalue} {/S:Argvalue} {/C:Argvalue} ]
:::[ - Args Must be encased in curly braces. Arg order does not matter ; Each Arg is optional. ]
:::[ * Valid Switches for COUT: /Save /Alt /Main ]
:::[ /Save - Stores the Y and X position at the start of the current expansion to .lY and .lX variables ]
:::[ /Alt - Switch console to alternate screen Buffer. Persists until /Main switch is used. ]
:::[ /Main - Restore console to main screen Buffer. Console default is the main buffer. ]
:::[ ]
:::[ USAGE: ]
:::[ * ArgValue Options ; '#' is an integer: ]
:::[ {/Y:up|down|#} {/Y:up#|down#|#} {/Y:#up|#down|#} {/X:left|right|#} {/X:left#|right#|#} {/X:#left|#right|#} ]
:::[ * note: {/Y:option} {/X:option} - 1 option only per Arg. ]
:::[ - directions: 'up' 'down' 'left' 'right' are relative to the cursors last position. ]
:::[ - /Y and /X options - #direction or direction#: ]
:::[ Positions the cursor a number of cells from the current position in the given direction. ]
:::[ Example; To move the cursor 5 rows up in the same column, without displaying any new text: ]
:::[ %COUT%{/Y:5up} ]
:::[ - '#' (Absolute position) is the column number {/X:#} or row number {/Y:#} the cursor ]
:::[ * Integers for absolute positions contained in variables must be Expanded: {/Y:%varname%} ]
:::[ is to be positioned at, allowing cursor position to be set on single or multiple axis. ]
:::[ * Absolute Y and X positions capped at line and column maximum of the console display. ]
:::[ * Exceeding the maximum Y positions the cursor at the start of the last line in the console display. ]
:::[ * Exceeding the maximum X positions the cursor at the start of the next line ]
:::[ ]
:::[ {/S:Output String} {/S:(-)Output String} {/S:Output String(+)} {/S:Output String(K)} {/S:Output String(.#.)} ]
:::[ * note: (-) Hide or (+) Show the Cursor during output of the string. ]
:::[ (K) Clears the row of text from the position (K) occurs. ]
:::[ Example; Delete 5 characters from the current row to the right of the curser: ]
:::[ %COUT%{/S:(.5.)} ]
:::[ {/C:VTcode} {/C:VTcode-VTcode} {/C:VTcode-VTcode-VTcode} ]
:::[ * note: Chain multiple graphics rendition codes using '-' ]
:::[ See: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#text-formatting ]
:::[ See also: https://www.rapidtables.com/web/color/RGB_Color.html ]
:::[=====================================================================================================================]
============================================== :# PreScript variable definitions
================== :# Screen Dimensions
Mode 100,30 & Cls
rem /* Get screen dimensions [lines] [columns]. Must be done before delayed expansion is enabled. */
For /F "tokens=1,2 Delims=:" %%G in ('Mode')Do For %%b in (%%H)Do For %%a in (%%G)Do Set "%%a=%%b"
rem /* NON ENGLISH VERSIONS : Users will need to Adjust to their desired console size */
If not defined columns (Set "columns=100"& Set "lines=30")
rem /* generate Vitual Terminal Escape Control Character */
For /F %%a in ( 'Echo prompt $E ^| cmd' )Do Set "\E=%%a"
rem /* https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences */
(Set \n=^^^
%= Newline variable for macro definitions. DO NOT MODIFY this line or above 2 lines. =%)
rem /* Cursor position codes - https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#simple-cursor-positioning */
Set "left=D"&Set "right=C"&Set "up=A"&set "down=B"
For /L %%n in (1 1 60)Do (Set "%%ndown=[%%nB"&Set "down%%n=[%%nB"& set "%%nup=[%%nA"&Set "up%%n=[%%nA")
For /L %%n in (1 1 240)Do (Set "%%nleft=[%%nD"&Set "left%%n=[%%nD"&set "%%nright=[%%nC"&set "right%%n=[%%nC")
Set COUT=For %%n in (1 2)Do If %%n==2 ( %\n%
If "!Args:}=!" == "!Args!" (CLS^&Echo/Usage Error. Args must be enclosed in curly braces ^& Exit /B 0) %\n%
Set ".Y=" ^& Set ".X=" ^& Set ".Str=" ^& Set ".C=" %\n%
Set "Arg1=" ^& Set "Arg2=" ^& Set "Arg3=" ^& Set "Arg4=" %\n%
For /F "Tokens=1,2,3,4 Delims={}" %%1 in ("!Args!")Do ( %\n%
Set "Arg1=%%~1" %\n%
Set "Arg2=%%~2" %\n%
Set "Arg3=%%~3" %\n%
Set "Arg4=%%~4" %\n%
) %\n%
If not "!Args:/Save=!" == "!Args!" (%\n%
Set "Cpos=" ^&Set "Char="%\n%
For /L %%l in (2 1 12)Do (%\n%
If not "!Char!" == "R" (%\n%
^<nul set /p "=%\E%[6n" %\n%
FOR /L %%z in (1 1 %%l) DO pause ^< CON ^> NUL%\n%
Set "Char=;"%\n%
for /F "tokens=1 skip=1 delims=*" %%C in ('"REPLACE /W ? . < con"') DO (Set "char=%%C")%\n%
If "!Cpos!" == "" (Set "Cpos=!Char!")Else set "Cpos=!Cpos!!char:R=!"%\n%
)%\n%
)%\n%
For /F "tokens=1,2 Delims=;" %%X in ("!Cpos!")Do Set ".lY=%%X" ^& Set ".LX=%%Y" %\n%
)%\n%
For %%i in (1 2 3 4)Do For %%S in (Y X C S)Do If not "!Arg%%i!" == "" ( %\n%
If not "!Arg%%i:/%%S:=!" == "!Arg%%i!" ( %\n%
Set "Arg%%i=!Arg%%i:/%%S:=!" %\n%
For %%v in ("!Arg%%i!")Do ( %\n%
If "%%S" == "Y" ( %\n%
If Not "!%%~v!" == "" ( %\n%
Set ".Y=%\E%!%%~v!" %\n%
)Else ( %\n%
Set /A ".Y=!Arg%%i!" %\n%
If !.Y! GEQ !Lines! (Set /A ".Y=Lines-1") %\n%
Set ".Y=%\E%[!.Y!d" %\n%
)) %\n%
If "%%S" == "X" ( %\n%
If Not "!%%~v!" == "" ( %\n%
Set ".X=%\E%!%%~v!" %\n%
)Else ( %\n%
Set /A ".X=!Arg%%i!" %\n%
If !.X! GEQ !Columns! (Set ".X=1"^& Set ".Y=%\E%!Down!") %\n%
Set ".X=%\E%[!.X!G" %\n%
)) %\n%
If "%%S" == "C" ( %\n%
Set ".C=%\E%[!Arg%%i!" %\n%
Set ".C=!.C:-=m%\E%[!" %\n%
Set ".C=!.C!m" %\n%
) %\n%
If "%%S" == "S" ( %\n%
Set ".Str=!Arg%%i!" %\n%
Set ".Str=!.Str:(-)=%\E%[?25l!" %\n%
Set ".Str=!.Str:(+)=%\E%[?25h!" %\n%
Set ".Str=!.Str:(K)=%\E%[K!" %\n%
Set ".Str=!.Str:(.=%\E%[!" %\n%
Set ".Str=!.Str:.)=P!" %\n%
) %\n%
))) %\n%
If not "!Args:/Main=!" == "!Args!" ( %\n%
^< nul Set /P "=%\E%[?1049l!.Y!!.X!!.C!!.Str!%\E%[0m" %\n%
)Else If not "!Args:/Alt=!" == "!Args!" ( %\n%
^< nul Set /P "=%\E%[?1049h!.Y!!.X!!.C!!.Str!%\E%[0m" %\n%
)Else ( ^< nul Set /P "=!.Y!!.X!!.C!!.Str!%\E%[0m" ) %\n%
)Else Set Args=
rem /* Simple subsecond delay macro. Uses call to a non existentent label # number of times to delay script execution. */
For /F "tokens=1,2 delims==" %%G in ('wmic cpu get maxclockspeed /format:value')Do Set /A "%%G=%%H/20" 2> nul
If not defined Maxclockspeed Set "Maxclockspeed=200"
Set "Hash=#"& Set "delay=(If "!Hash!" == "#" (Set /A "Delay.len=Maxclockspeed")Else Set "Delay.len=#")& For /L %%i in (1 1 !Delay.Len!)Do call :[_false-label_] 2> Nul"
============================================== :# Script Body [Demo]
rem /* Enable Delayed Expansion after macro definiton in order to expand macro. */
Setlocal EnableDelayedExpansion & CD "%TEMP%"
rem /* Usage examples */
%COUT%{/X:10}{/Y:5}{/C:34}{"/S:(-)hello there^^^!"}
%Delay%
rem /* Example use of mixed foreground / background color and other graphics rendition properties */
%COUT%{"/C:31-1-4-48;2;0;80;130"}{/S:Bye for now.}{/Y:down}
%Delay%
%COUT%{/Y:up}{/C:35}{/S:again}{/X:16}
%Delay%
%COUT%{"/S:(K)^_^"}{/X:right}{/C:32}{/Y:down} /Save
%Delay%
rem /* Switch to Alternate screen buffer: /Alt */
%COUT%{"/S:(-)(K)^_^"}{/X:.lX+1}{/Y:6}{/C:33}{/Y:down} /Alt
%COUT%{"/S:They'll be back"}{/Y:down}{/X:left}{/C:31}
%Delay%
rem /* Return to Main screen buffer: /Main */
%COUT%{/X:3left}{/Y:5up}{"/S:That's all folks."} /Save /Main
%Delay%
rem /* restore cursor position /Save .lX value with +7 offset ; Overwrite all and delete 6 following characters:(.6.) ; restore cursor: (+) */
%COUT%{/X:10left}{/S:How(.6.)(+)}{/C:32}
rem /* The same as the above line using VT codes manually. */
::: <nul Set /P "=%\E%[10D%\E%[32mHow%\E%[6P%\E%[?25l"
%Delay%
%COUT%{/Y:100}
Endlocal
Goto :eof
Решение 1
С помощью Notepad++ можно вставить Backspace ←символ (ASCII 0x08) напрямую, используя панель вставки кодов ASCII («Правка» > «Панель символов»).
Мое решение - вставить[BS]
символ напрямую, а затем, как и другие решения, опубликованные здесь, используйте его несколько раз для удаления предыдущих символов:
Код
@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
Скриншот Блокнота++
Выход
Решение 2
Другая возможность — использовать cecho (команду echo с поддержкой цветов) для вставки Carriage Return ↵символа Юникода (U+000D):
Код
@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
Примечание:
cecho_x64.exe
работает значительно быстрее на моей машине, чем
cecho.exe
.