如何覆盖批处理文件的命令输出中的同一行


13

我想写一些状态信息来代替我做某事时的最后一行。

在以下示例bat文件中,我希望文本在命令输出的同一行上Step 2覆盖Step 1

echo off

echo Step 1
REM Do some stuff...

echo Step 2
REM do some other stuff...

Answers:


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

我通过查看由Dave Benham编写的名为CharLib的批处理脚本字符操作库中的代码找到了这个答案。

该库能够创建1..255范围内的所有字符。

有关更多信息,请参见标题为“是否可以将字符转换为其ASCII值?”的线程

编辑2017-4-26: 看来上面的代码不再起作用。我不确定这种行为何时会改变,但肯定可以正常工作。在CR后字符=现在得到由剥离set命令。嗯,这似乎是setXP和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...

2
对我来说,这只是打印“ Step 1Step 2”,而不是在屏幕上仅显示“ Step 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 2End

这是我使用特殊的ASCII字符8(即退格键)所做的。因为我不知道如何用cmd编写它,所以我使用了:EVALUATE函数,该函数运行VBS Chr()函数,并将退格字符放入变量中result。如果有人知道更好的方法,请提出建议。


1
在PowerShell中,您还可以将其存储$host.ui.RawUI.CursorPosition到变量中,然后再将其还原,以使光标跳回原来的位置并覆盖输出。这只是PowerShell的一个选项,但可能比您的VBS东西还干净:-)
mihi 2012年

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 (复制/ Z“%〜dpf0” nul) DO (set "cr=%%a")

要查看结果,请输入: setlocal EnableDelayedExpansion & echo asfasdhlfashflkashflksa!CR!***

输出将是: ***asfasdhlfashflkashflksa

上面的@davour答案也很漂亮,但是@timfoden的答案对我不起作用。


@timfoden的答案无效,因为!CR!应该在上一步的末尾进行。此外,您还可以!CR!代替所有这些%BSPACE%s!并用空格填充:set /p "=.!CR!End. " <NUL&echo:
Zimba,

3

你不能 通常,您可以通过在文件中包含一个回车符(0x0D)来实现这种目的,该字符会将光标返回到同一行的第一列。但是在这种情况下,它不起作用。CR只是被默默地吃掉了。

此外,在其中获得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"
Zimba,

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.

仅当Step 1 Step 2 Step 3长度都相同时,这才有效。如果不是,则set /p保留第一个文本。不确定如何解决此问题。
Ste

可以通过在下一个提示中使用其他空格字符来解决该问题。覆盖以前的所有字符。与相对的例子 。交换角色。set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NULset /p "=Step 2!Newline!" <NULSPACE
Ste

如果前几行较长,则添加空格以消除多余的字符,或者从行尾到开头退格,或者仅退格到多余的字符。
津巴

0

您需要一个类似curses或的屏幕光标库ncurses,但是我对它们的用法不太熟悉。这两个库都是为Unix系统开发的,但是您可以在Windows(在Cygwin环境GnuWin32中)中找到它们。

我不知道以DOS样式的批处理文件访问它们的任何简便方法。使用编译语言进行编程可能会更好。看一下Ncurses HOWTO,可以更好地了解它是否有用。


诅咒仅适用于终端和终端仿真器。它们并没有真正映射到Windows的本机控制台API。
乔伊,

无需外部库;与CMD工具配合使用时效果很好。
Zimba

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 ↵ Unicode字符(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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.