Тема: CMD/BAT: вывод текста без переноса на новую строку
Как известно, команда «echo», используемая в пакетных файлах для вывода текста, добавляет символы 0x0D, 0x0A (Carriage Return и Line Feed). Чтобы избежать этого, обычно используют какую-либо внешнюю утилиту, эмулирующую вывод и не добавляющую перенос на новую строку. Однако существует способ добиться такого поведения, используя только встроенные средства командного процессора (обратите внимание на пробелы в конце команд!):
@echo off
<nul set /p strTemp=Весь этот текст
<nul set /p strTemp=будет находиться
<nul set /p strTemp=на одной строке.
Весь этот текст будет находиться на одной строке.
То есть, мы используем ввод с устройства «nul» в команде «set /p» для эмуляции команды «echo».
Если нужна новая строка, следует, после использования вышеуказанного метода, использовать команду «echo.»:
@echo off
<nul set /p strTemp=Весь этот текст
<nul set /p strTemp=будет находиться
<nul set /p strTemp=на одной строке.
echo.
echo А этот - уже на следующей.
Весь этот текст будет находиться на одной строке.
А этот - уже на следующей.
Содержимое использованной переменной окружения «strTemp» при этом не изменяется:
@echo off
set StrTemp=Некое Значение
echo Before: strTemp=[%strTemp%].
<nul set /p strTemp=Весь этот текст
<nul set /p strTemp=будет находиться
<nul set /p strTemp=на одной строке.
echo.
echo After: strTemp=[%strTemp%].
Before: strTemp=[Некое Значение].
Весь этот текст будет находиться на одной строке.
After: strTemp=[Некое Значение].
Данный метод можно оформить, например, в виде внутренней процедуры (EchoWithoutCrLf), что делает его нагляднее за счёт использования кавычек:
@echo off
call :EchoWithoutCrLf "Весь этот текст "
call :EchoWithoutCrLf "будет находиться "
call :EchoWithoutCrLf "на одной строке."
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура EchoWithoutCrLf
rem
rem %1 : текст для вывода.
rem ==========================================================================
:EchoWithoutCrLf
<nul set /p strTemp=%~1
exit /b 0
rem ==========================================================================
Весь этот текст будет находиться на одной строке.
Используя требуемое количество символов BackSpace (0x08) при выводе текста, и аналогичное количество символов Space (0x20) и BackSpace (0x08) после вывода текста, можно получить вывод поверх предыдущего текста. Как это выглядит:
1) выводится некий текст длины S символов + S символов BackSpace (для того, чтобы вернуть курсор на начало строки);
2) делается пауза для демонстрации выведенного текста;
3) выводится S символов пробелов (чтобы гарантированно затереть ранее выведенный текст) + S символов BackSpace (для того, чтобы опять вернуть курсор на начало строки).
Здесь важно помнить, что если длина текста превысит ширину окна консоли, то текст будет автоматически перенесён на следующую строку, и вернуть курсор в первоначальную позицию, без сторонних средств, не удастся.
1. Использование команды «set /p»:
@echo off
<nul set /p strTemp=Можно делать вывод
pause > nul
<nul set /p strTemp=
<nul set /p strTemp=и поверх предыдущего текста.
pause > nul
<nul set /p strTemp=
2. Использование процедуры «EchoWithoutCrLf»:
@echo off
call :EchoWithoutCrLf "Можно делать вывод"
pause > nul
call :EchoWithoutCrLf " "
call :EchoWithoutCrLf "и поверх предыдущего текста."
pause > nul
call :EchoWithoutCrLf " "
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура EchoWithoutCrLf
rem
rem %1 : текст для вывода.
rem ==========================================================================
:EchoWithoutCrLf
<nul set /p strTemp=%~1
exit /b 0
rem ==========================================================================
Чтобы не рассчитывать потребное количество BackSpace'ов и Space'ов вручную, подобный вывод также можно оформить в виде процедуры, точнее, пары основных процедур (процедура «EchoOut» выводит текст, процедура «EchoClear» «стирает» его) и нескольких вспомогательных («FillBackSpace», «FillSpace», «FillString» и «StrLen», см. комментарии в коде; в процедурах используется методика CMD/BAT: возврат значений из процедур через параметры). Вызывайте их с одной и той же строкой в качестве параметра (в процедуре «EchoClear» переданная строка используется только для подсчёта длины). Таким образом, например, можно эмулировать команду «pause» без переноса курсора на новую строку после вывода текста «Для продолжения нажмите любую клавишу . . .». Также, чтобы каждый раз не дублировать один и тот же текст при вызове процедур «EchoOut»/«EchoClear», можно использовать переменную окружения:
@echo off
set strText="Конечно, Ваш редактор должен позволять вводить символ BackSpace (0x08)."
call :EchoOut %strText%
pause > nul
call :EchoClear %strText%
set strText="Например, редактор Far Manager'а сие позволяет, используйте Ctrl-Q, Ctrl-H."
call :EchoOut %strText%
pause > nul
call :EchoClear %strText%
rem Эмулируем команду PAUSE без переноса на новую строку
set strText="Нажмите любую клавишу для продолжения..."
call :EchoOut %strText%
pause > nul
call :EchoClear %strText%
echo Продолжаем вывод в той же строке...
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура EchoOut
rem
rem %1 : текст для вывода.
rem ==========================================================================
:EchoOut
rem ---- Получаем строку, заполненную символами BackSpace (0x08) в переменную strBackSpace
call :FillBackSpace "%~1" strBackSpace
<nul set /p strTemp=%~1%strBackSpace%
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура EchoClear
rem
rem %1 : текст для очистки; используется только для получения длины строки.
rem ==========================================================================
:EchoClear
rem ---- Получаем строку, заполненную символами Space (0x20) в переменную strSpace
call :FillSpace "%~1" strSpace
rem ---- Получаем строку, заполненную символами BackSpace (0x08) в переменную strBackSpace
call :FillBackSpace "%~1" strBackSpace
<nul set /p strTemp=%strSpace%%strBackSpace%
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура FillBackSpace
rem
rem %1 : строка текста; используется только для получения длины строки.
rem %2 : имя переменной для возврата строки, заполненной символами BackSpace (0x08)
rem ==========================================================================
:FillBackSpace
setlocal enableextensions enabledelayedexpansion
rem ---- Получаем длину переданной строки в переменную intStrLen ---------
call :StrLen "%~1" intStrLen
rem ---- Получаем строку, заполненную символами BackSpace (0x08) в переменную strTempString
call :FillString "" %intStrLen% strTempString
endlocal & set %~2=%strTempString%
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура FillSpace
rem
rem %1 : строка текста; используется только для получения длины строки.
rem %2 : имя переменной для возврата строки, заполненной символами Space (0x20)
rem ==========================================================================
:FillSpace
setlocal enableextensions enabledelayedexpansion
rem ---- Получаем длину переданной строки в переменную intStrLen ---------
call :StrLen "%~1" intStrLen
rem ---- Получаем строку, заполненную символами Space (0x20) в переменную strTempString
call :FillString " " %intStrLen% strTempString
endlocal & set %~2=%strTempString%
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура FillString
rem
rem %1 : символ или строка текста
rem %2 : число повторов
rem %3 : имя переменной для возврата строки, заполненной %2 раз символами %1
rem ==========================================================================
:FillString
setlocal enableextensions enabledelayedexpansion
set strTempString=
for /l %%i in (1,1,%~2) do (
set strTempString=!strTempString!%~1
)
endlocal & set %~3=%strTempString%
exit /b 0
rem ==========================================================================
rem ==========================================================================
rem Процедура StrLen
rem
rem %1 : строка текста
rem %2 : имя переменной для возврата длины строки
rem ==========================================================================
:StrLen
setlocal enableextensions enabledelayedexpansion
set strString=%~1
set /a intStrLen = 0
for /l %%i in (0,1,1024) do (
set strTempString=!strString:~%%i,1!
if [!strTempString!] neq [] (
set /a intStrLen+=1
)
)
endlocal & set /a %~2=%intStrLen%
exit /b 0
rem ==========================================================================
Осталось добавить, что использование данного метода я увидел в коде amel27 на форуме OSzone.net.