Как перезаписать одну и ту же строку в выводе команды из командного файла

13

Я хочу написать некоторую информацию о состоянии, которая заменяет последнюю строку, когда я что-то делаю.

В следующем примере 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...
timfoden
источник
2
Для меня это просто печатает «Шаг 1 Шаг 2» вместо того, чтобы просто «Шаг 2» на экране.
galmok
@galmok Это тоже начало происходить со мной, но я уверен, что никогда не использовал (так как у меня есть скрипт, который раньше работал идеально, недавно изменил поведение, которое вы описываете.) Похоже, что setкоманда теперь удаляет любые Символы CR и LF (а также пробелы) после =. Попробуйте поместить символ без пробелов между =и!ACSII_13!
timfoden
Есть способ сделать все это ... Я на самом деле пришел посмотреть, заметил ли кто-то еще, потому что я хотел узнать, обнаружили ли они, как далеко это зашло. ... Могу ли я написать ответ на переполнение стека? ИЛИ .. как вопрос и сразу на него ответить? Я полагаю, я мог бы написать это в форме вопроса о том, что вы могли бы сделать с этим ... Я должен пойти съесть что-нибудь, но я обновлю это со ссылкой для вас.
Брент Риттенхаус
Напишите! ASCII_13! после шага 1 , чтобы предотвратить зачистки, поэтому на шаге 2 вы бы код:set /p "=Step 2 " <NUL
Zimba
6

Чтобы ответить на вопрос:

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

Это возвращение я делаю со специальным символом 8 ASCII, который является backspace. Поскольку я не знаю, как написать это в cmd, я использую функцию: EVALUATE, которая запускает функцию VBS Chr () и помещает символ возврата в переменную result. Если кто-то знает лучший способ, пожалуйста, сообщите.

Давор Йосипович
источник
1
В PowerShell вы также можете сохранить $host.ui.RawUI.CursorPositionпеременную и позже восстановить ее, чтобы курсор вернулся назад и перезаписал вывод. Только вариант для PowerShell, но может быть немного чище, чем ваш 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

ОБЪЯСНЕНИЕ:

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 мне не помог.

Сурав Гош
источник
Ответ @ timfoden не сработал, потому что! CR! должен идти в конце предыдущего шага. Кроме того, вместо всех этих% BSPACE% s вы также можете! CR! и заполните пробелами:set /p "=.!CR!End. " <NUL&echo:
Зимба
3

Ты не можешь Обычно этого можно добиться, включив в файл символ возврата каретки (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перед выходным шагом. Будет мерцать, но вы всегда будете писать в верхнем левом углу. И ударить все, что было видно в консоли (поэтому я бы не рекомендовал это); большинству пользователей это не нравится.

детеныш
источник
Хорошо, у меня было подозрение, что это было невозможно сделать с чистой командной строкой. Если я хочу, чтобы утилита делала это, я с таким же успехом мог бы поместить все это в утилиту. То, что я действительно хотел, было просто видимым обратным отсчетом, который ждет 5 секунд, отсчитывая каждую секунду до конца.
благосклонность
4
Трепет: Если вы работаете в Vista или более поздней версии, то timeout 5будет работать.
Джои
Большой! благодарю вас! Тайм-аут 5 работает!
благоговение
4
Я должен был опубликовать свою настоящую проблему в первый раз ...
благосклонность
Конечно вы можете; просто добавьте возврат каретки после шага 1! Кроме того, вот код для возврата каретки без использования текстового редактора:for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
Зимба
1

Получить символ новой строки, написать следующий шаг, вернуться к началу строки, написать следующую строку:

@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
источник
Это будет работать, только если Step 1 Step 2 Step 3они все одинаковой длины. Если нет, то текст первого set /pостается. Не уверен, как это исправить.
Ste
Эту проблему можно исправить, используя дополнительные пробельные символы в следующем приглашении. чтобы покрыть любые предыдущие символы. Пример set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NUL в отличие от set /p "=Step 2!Newline!" <NUL. Обмен SPACEна персонажа.
Ste
Если предыдущие строки длиннее, добавьте пробелы, чтобы убрать лишние символы, или возврат к концу строки в начало, или просто возврат к дополнительным символам.
Зимба
0

Вам понадобится библиотека экранных курсоров, например cursesили ncurses, но я не слишком знаком с их использованием. Обе библиотеки были разработаны для систем Unix, но вы можете найти их для Windows (в среде Cygwin или GnuWin32 ).

Я не знаю ни одного простого способа получить к ним доступ в пакетном файле в стиле DOS. Возможно, вам лучше программировать на скомпилированном языке. Взгляните на Ncurses HOWTO, чтобы лучше понять, будет ли это полезно.

шарлатан
источник
Проклятия в значительной степени предназначены только для терминалов и эмуляторов терминалов. На самом деле они не отображаются на консольный API Windows.
Джои
Нет необходимости во внешних библиотеках; отлично работает с инструментами CMD.
Зимба
0

Решение 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

Скриншот Notepad ++

Пакетная перезапись Windows


Вывод

CMD выход


Решение 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

NB: cecho_x64.exeна моей машине работает значительно быстрее, чем cecho.exe.

andronoid
источник