Windows 批处理:没有换行的回显
Posted
技术标签:
【中文标题】Windows 批处理:没有换行的回显【英文标题】:Windows batch: echo without new line 【发布时间】:2011-10-29 15:28:36 【问题描述】:Linux shell 命令echo -n
在输出末尾抑制换行符的 Windows 批处理等效项是什么?
想法是写在循环内的同一行。
【问题讨论】:
见 [***.com/questions/245395/… [1]: ***.com/questions/245395/… 这让我几乎疯了..我知道echo
可以接受-n
,但在cmd.exe
上它就是行不通^^
@panny - 尽管名称相同,但 echo 在 Windows 和 Posix 之间并不是同一个命令。和 nslookup 一样,有不同的选项。因此,在与 Windows 相关的问题中,“我知道 echo
可以接受 -n
”的评论是不正确的。
@user66001 - Windows 上的“echoX -n”在今天发布的以下答案中有详细说明。
@Bilbo - 不确定您是否使用批处理,但 99% 的时间我都在使用它来帮助其他人在非我的设备上自动执行某些操作。使用 3rd 方实用程序提供批处理文件并不容易或有效。 (特别是如果这个第 3 方 util 是 .exe 变种,考虑到我最初评论 7 年后的病毒格局)。
【参考方案1】:
我发现这个名为“EchoPart.bat”的简单单行批处理文件非常有用。
@echo | set /p=%*
然后我甚至可以在交互式 CMD 行上或作为快捷方式的一部分编写类似下面的行。它开辟了一些新的可能性。
echopart "Hello, " & echopart "and then " & echo Goodbye
如果您在批处理文件中使用它,则可以从参数变量而不是不可变字符串中获取文本。例如:
@echopart Hello %* & @echo , how are you?
因此在“SayHello.bat”中执行这一行允许:
甚至……
玩得开心,玩得开心!
【讨论】:
我知道批处理文件行“@echo Hello %*,你好吗?”会做同样的事情,但关于“EchoPart.bat”的要点是它在不添加换行符的情况下输出其文本。这意味着您可以像 BASH 中的“cat”命令一样连接文本。尽管您不必通过管道传输命令,只需按顺序执行它们即可。在我的示例测试中,我以直接回声结束,但我本可以以另一个 echoPart 结束。 例如比较命令行“dir”和“echopart Local &dir”。发现区别了吗?【参考方案2】:使用 jscript:
@if (@X)==(@Y) @end /*
@cscript //E:JScript //nologo "%~nx0" %*
@exit /b %errorlevel%
*/if(WScript.Arguments.Count()>0) WScript.StdOut.Write(WScript.Arguments.Item(0));
如果它被称为 write.bat,你可以像这样测试它:
call write.bat string & echo _Another_String_
如果你想使用 powershell 但你可以使用 cmd 定义的变量:
set str=_My_StrinG_
powershell "Write-Host -NoNewline ""%str%"""" & echo #Another#STRING#
【讨论】:
【参考方案3】:使用来自Bill Stewart的极好的“Shell Scripting Toolkit”中的 EchoX.EXE 如何在 Windows Cmd 脚本中禁止换行:
@Echo Off
Rem Print three Echos in one line of output
EchoX -n "Part 1 - "
EchoX -n "Part 2 - "
EchoX "Part 3"
Rem
给予:
Part 1 - Part 2 - Part 3
empty line
d:\Prompt>
这个用法的帮助是:
Usage: echox [-n] message
-n Do not skip to the next line.
message The text to be displayed.
该实用程序小于 48K,并且应该存在于您的路径中。它可以做的更多事情:- 在不移动到下一行的情况下打印文本- 在一定宽度内打印向左、居中或向右对齐的文本- 使用制表符、换行符和返回- 以前景色和背景色打印文本
该工具包包含另外十二个出色的脚本技巧。The download page 还包含三个其他有用的工具包。
【讨论】:
【参考方案4】:回显前面有空格,没有换行符
正如Pedro 之前所说,没有换行符和前面有空格的回显可以工作(前提是“9”是一个真正的[BackSpace])。
<nul set /p=.9 Hello everyone
我在使用新控制台在 Windows 10 中运行时遇到了一些问题,但通过以下方式进行管理。 在 CMD 类型中:
echo .◘>bs.txt
我通过按 [Alt] + [8] 得到“◘” (实际符号可能因代码页而异)。
然后很容易使用 Notepad.exe 将结果从“bs.txt”复制到需要的地方。
@echo off
<nul set /p "_s=.◘ Hello everyone"
echo: here
【讨论】:
【参考方案5】:受此问题答案的启发,我制作了一个简单的计数器批处理脚本,该脚本不断在同一行打印进度值 (0-100%)(覆盖前一个)。也许这对于寻求类似解决方案的其他人也很有价值。
备注:*
是不可打印字符,需要使用[Alt
+ Numpad 0
+ Numpad 8
]组合键输入,即backspace
字符.
@ECHO OFF
FOR /L %%A in (0, 10, 100) DO (
ECHO|SET /P="****%%A%%"
CALL:Wait 1
)
GOTO:EOF
:Wait
SET /A "delay=%~1+1"
CALL PING 127.0.0.1 -n %delay% > NUL
GOTO:EOF
【讨论】:
【参考方案6】:我根据@arnep 的想法做了一个函数:
echo|set /p="Hello World"
在这里:
:SL (sameline)
echo|set /p=%1
exit /b
与call :SL "Hello There"
一起使用
我知道这没什么特别的,但我花了很长时间才想到它,我想我会把它贴在这里。
【讨论】:
【参考方案7】:DIY cw.exe
(控制台写入)实用程序
如果您没有找到开箱即用的现成产品,您可以 DIY。有了这个cw
实用程序,您可以使用各种字符。至少,我愿意这么认为。请对其进行压力测试并告诉我。
工具
您只需要安装.NET,这在当今很常见。
材料
输入/复制粘贴了一些字符。
步骤
-
使用以下内容创建
.bat
文件。
/* >nul 2>&1
@echo off
setlocal
set exe=cw
for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d /o:-n "%SystemRoot%\Microsoft.NET\Framework\*csc.exe"') do set "csc=%%v"
"%csc%" -nologo -out:"%exe%.exe" "%~f0"
endlocal
exit /b %errorlevel%
*/
using System;
namespace cw
class Program
static void Main()
var exe = Environment.GetCommandLineArgs()[0];
var rawCmd = Environment.CommandLine;
var line = rawCmd.Remove(rawCmd.IndexOf(exe),exe.Length).TrimStart('"');
line = line.Length < 2 ? "\r" : line.Substring(2) ;
Console.Write(line);
运行它。
现在您有了一个不错的 4KB 实用程序,因此您可以删除 .bat
。
或者,您可以将此代码作为子例程插入到任何批处理中,将生成的.exe
发送到%temp%
,在您的批处理中使用它并在完成后将其删除。
如何使用
如果你想写一些没有换行的东西:cw Whatever you want, even with "", but remember to escape ^|, ^^, ^&, etc. unless double-quoted, like in "| ^ &".
如果您想要回车(转到行首),只需运行cw
所以从命令行试试这个:
for /l %a in (1,1,1000) do @(cw ^|&cw&cw /&cw&cw -&cw&cw \&cw)
【讨论】:
我受到您的回答的启发,并使用 Go 和 this 为 Azure Pipelines 创建了附带任务的 this 小工具。它只是抓取通过管道输入的标准输出并以特定格式输出以供构建使用。谢谢!【参考方案8】:来自here
<nul set /p =Testing testing
也可以使用空格开头的回显
echo.Message goes here
【讨论】:
【参考方案9】:示例 1:这有效并产生退出代码 = 0。这很好。 注意“。” , 直接在 echo 之后。
C:\Users\phife.dog\gitrepos\1\repo_abc\scripts # @echo。| set /p JUNK_VAR=这是一条类似于 Linux echo -n 会显示的消息... & echo %ERRORLEVEL%
这是一条显示的消息,类似于 Linux echo -n 会显示它... 0
示例 2:这可行但会产生退出代码 = 1。这很糟糕。 请注意回显后缺少“.”。这似乎是不同的。
C:\Users\phife.dog\gitrepos\1\repo_abc\scripts # @回声 | set /p JUNK_VAR=这是一条类似于 Linux echo -n 会显示的消息... & echo %ERRORLEVEL%
这是一条显示的消息,就像 Linux echo -n 会显示它... 1
【讨论】:
【参考方案10】:使用set
和/p
参数,您可以在没有换行符的情况下回显:
C:\> echo Hello World
Hello World
C:\> echo|set /p="Hello World"
Hello World
C:\>
Source
【讨论】:
管道非常慢,因为它创建了两个额外的 cmd 任务,更快的是<nul set /p =Hello
。 set /p
不能将等号作为第一个字符或空格/制表符回显。
在我的系统上快了将近 15 倍
在 "Hello World" 周围添加引号,以防止 d 后出现多余的空格。
警告:这会将 ERRORLEVEL 更改为 1。请参阅@xmechanix 的回答。
@user246694 < nul
是来自NUL
设备的重定向。它不包含任何内容,但这足以让set /p
停止等待用户输入【参考方案11】:
您可以使用 set /p 命令取消新行。 set /p 命令不能识别空格,因为您可以使用点和退格字符使其识别。你也可以把一个变量当成内存,把你想打印的东西存储在里面,这样就可以打印变量而不是句子了。例如:
@echo off
setlocal enabledelayedexpansion
for /f %%a in ('"prompt $H & for %%b in (1) do rem"') do (set "bs=%%a")
cls
set "var=Hello World! :)"
set "x=0"
:loop
set "display=!var:~%x%,1!"
<nul set /p "print=.%bs%%display%"
ping -n 1 localhost >nul
set /a "x=%x% + 1"
if "!var:~%x%,1!" == "" goto end
goto loop
:end
echo.
pause
exit
通过这种方式,您可以打印任何内容而无需换行。我已经让程序一个一个地打印字符,但是您也可以通过更改循环来使用单词而不是字符。
在上面的示例中,我使用了“enabledelayedexpansion”,因此 set /p 命令无法识别“!”字符并打印一个点而不是那个。我希望你不要使用感叹号“!” ;)
【讨论】:
【参考方案12】:作为@xmechanix 答案的补充,我注意到通过将内容写入文件:
echo | set /p dummyName=Hello World > somefile.txt
这将在打印字符串的末尾添加一个额外的空格,这可能会带来不便,特别是因为我们试图避免在末尾添加一个新行(另一个空白字符)字符串。
幸运的是,引用了要打印的字符串,即使用:
echo | set /p dummyName="Hello World" > somefile.txt
将打印最后没有任何换行符或空格字符的字符串。
【讨论】:
如果您不在World
和>
之间添加空格,多余的空格应该会消失...
@aschipfl 试过了,不行。
引用变量方法,set 命令的一个未记录的特性,通常是我认为应该使用的方法,因为它适用于所有版本的 WIndows NT(如果我记得,还有 9x)。也就是说,您将变量名称包装到引号中的值的末尾。 Set/P 也是如此。
IE:回声 |设置 /p "dummyName=Hello World" >somefile.txt
@aschipfl 如果你不做引号,会出现一个额外的空格,你做一个管道。 xxd 是一个十六进制转储实用程序,因此我们可以看到例如set /p="abc"<nul|xxd -p
显示 616263
而 set /p=abc<nul|xxd -p
给出 61626320
【参考方案13】:
也许这就是你要找的东西,它是一个老式的脚本......:P
set nl=^& echo.
echo %nl%The%nl%new%nl%line%nl%is%nl%not%nl%apparent%nl%throughout%nl%text%nl%
echo only in prompt.
pause
或者您可能试图替换当前行而不是写入新行? 您可以通过删除“。”之后的“%bs%”来进行试验。签名并在“示例消息”之后隔开其他“%bs%”。
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "bs=%%a"
<nul set /p=.%bs% Example message %bs%
pause
我觉得这真的很有趣,因为它使用变量的目的与预期目的不同。如您所见,“%bs%”代表退格键。第二个“%bs%”使用退格在“示例消息”之后添加空格来分隔“暂停命令的输出”,而实际上并未在“示例消息”之后添加可见字符。但是,这也可以使用常规百分比符号。
【讨论】:
我到处都能看到这个set nl=^& echo.
把戏,变量的名称具有误导性。 %nl% 不是换行符字符:它扩展为&echo.
,所以最后你每次都运行一个新的echo
命令,因此是换行符。您可以查看echo "%nl%The%nl%new%nl%line%nl%is%nl%not%nl%apparent%nl%throughout%nl%text%nl%"
。你得到"& echo. The& echo. new& echo. line& echo. is& echo. not& echo. apparent& echo. throughout& echo. text& echo. "
,揭示了诀窍。输出是相同的,但不是出于您建议的原因。
不仅“技巧”令人讨厌,ECHO.xxx
实际上在作为命令执行之前被解析为文件,所以它'如果当前目录中有一个名为ECHO
的文件,则会失败。更好的是echo(
【参考方案14】:
这里的答案较晚,但是对于需要在一行中写入特殊字符的任何人,如果他们发现dbenham 的答案太长了大约 80 行并且其脚本可能会中断(可能是由于用户输入)仅使用 set /p
的限制,最简单的方法是将 .bat 或 .cmd 与已编译的 C++ 或 C 语言可执行文件配对,然后只使用 cout
或 printf
字符。如果您正在显示一种进度条或使用字符的东西,这也将允许您轻松地多次写入一行,就像 OP 显然一样。
【讨论】:
@jiggunjer 你确定?printf
来自 Win-7 的 cmd
窗格给了我 "'printf' is not recognized as an internal or external command, operable program or batch file."
printf
不是 Windows 原生的。这是一个 Windows 问题。
@kayleeFrye_onDeck 我假设您的评论是针对jiggunjer,而不是我;我在我的问题中建议,在格式很重要的情况下,C 和 C++ 可以用作 shell 命令的相当独立于平台的替代方案。
请原谅我的父亲,因为我略读了。
但是需要正确解析shell的输入。例如,这样的程序如何打印引号?【参考方案15】:
SET /P 中去除空白的解决方案:
诀窍是你可以在 DOS 的文本编辑器 EDIT 中调用的退格字符。要在 EDIT 中创建它,请按 ctrlP+ctrlH。 我会把它贴在这里,但这个网页无法显示它。虽然它在记事本上可见(它很奇怪,就像一个中间有一个白色圆圈的黑色小矩形)
所以你写这个:
<nul set /p=.9 Hello everyone
点可以是任何字符,它只是告诉 SET /P 文本从那里开始,在空格之前,而不是在“Hello”。 “9”是我无法在此处显示的退格字符的表示形式。你必须把它而不是 9,它会删除 "." ,之后你会得到这个:
Hello Everyone
代替:
Hello Everyone
希望对你有帮助
【讨论】:
我忘了告诉你,它在 Windows 7 中工作它不能在命令行中工作,只能在批处理中工作。对于没有获得 char 的任何人,请下载此示例:pecm.com.sapo.pt/SET_with_backspace_char.txt Echo 也是如此 ... 所以,在进行了相当彻底的搜索之后,我在网上的任何地方都没有找到这个。这可能是我第一次真正发现了一些东西,而且很幸运。如果您将 cmd 提示符置于传统模式并使用正确的字体,则对于那些不知道您可以输入控制字符的人。 ...但是,如果您只是将任何内容重定向到文件或 >con 它也可以。严重地。将其完全粘贴到您的命令提示符中:“echo ←c◙◙○○ Harharhar!!◙○○ -------------◙◙○○ 我是最糟糕的!?:'(○ ♪ ○NOPE!•♪○ 我感觉棒极了!Hazzah-le-oop!◙◙○ 我是程序员,听我说……什么。◙>骗局。 好的,我希望我在其他人之前发现了这一点,但是......这似乎取决于不在 unicode 代码页中。您可以将起始的存储在一个变量中,执行 chcp 437,将集合设置在一个变量中,或者输出它,然后切换回来(它应该仍然输出)。我还在玩它。 另外,有人知道为什么 ←c 会清除屏幕吗?!我在网上的任何地方都找不到这样的实例。尽管您似乎也可以在两个字符之间使用空格,但具体来说就是这种组合。对于任何其他角色,它似乎只是......删除第一个角色。我不明白...【参考方案16】:这是另一种方法,它使用具有 -NoNewLine 参数的 Powershell Write-Host,将其与 start /b
结合使用,它提供了与批处理相同的功能。
NoNewLines.cmd
@ECHO OFF
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 1 - ';Write-Host -NoNewLine 'Result 2 - ';Write-Host -NoNewLine 'Result 3 - '"
PAUSE
输出
Result 1 - Result 2 - Result 3 - Press any key to continue . . .
下面这个略有不同,并不完全像 OP 想要的那样工作,但很有趣,因为每个结果都会覆盖前面模拟计数器的结果。
@ECHO OFF
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 1 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 2 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 3 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 4 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 5 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 6 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 7 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 8 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 9 - '"
PAUSE
【讨论】:
【参考方案17】:简单的 SET /P 方法的限制在 Windows 版本之间略有不同。
前导引号可能会被删除
前导空白可能会被剥离
前导 =
会导致语法错误。
更多信息请参见http://www.dostips.com/forum/viewtopic.php?f=3&t=4209。
jeb 在Output text without linefeed, even with leading space or = 上发布了一个巧妙的解决方案,解决了大多数问题。我改进了该方法,使其可以在从 XP 开始的任何版本的 Windows 上安全地打印任何有效的批处理字符串,而无需换行。请注意,:writeInitialize
方法包含可能无法很好地发布到站点的字符串文字。包含一个描述字符序列应该是什么的注释。
:write
和:writeVar
方法经过优化,使用我修改过的 jeb 的 COPY 方法只写入包含麻烦的前导字符的字符串。使用更简单、更快速的 SET /P 方法编写不麻烦的字符串。
@echo off
setlocal disableDelayedExpansion
call :writeInitialize
call :write "=hello"
call :write " world!%$write.sub%OK!"
echo(
setlocal enableDelayedExpansion
set lf=^
set "str= hello!lf!world^!!!$write.sub!hello!lf!world"
echo(
echo str=!str!
echo(
call :write "str="
call :writeVar str
echo(
exit /b
:write Str
::
:: Write the literal string Str to stdout without a terminating
:: carriage return or line feed. Enclosing quotes are stripped.
::
:: This routine works by calling :writeVar
::
setlocal disableDelayedExpansion
set "str=%~1"
call :writeVar str
exit /b
:writeVar StrVar
::
:: Writes the value of variable StrVar to stdout without a terminating
:: carriage return or line feed.
::
:: The routine relies on variables defined by :writeInitialize. If the
:: variables are not yet defined, then it calls :writeInitialize to
:: temporarily define them. Performance can be improved by explicitly
:: calling :writeInitialize once before the first call to :writeVar
::
if not defined %~1 exit /b
setlocal enableDelayedExpansion
if not defined $write.sub call :writeInitialize
set $write.special=1
if "!%~1:~0,1!" equ "^!" set "$write.special="
for /f delims^=^ eol^= %%A in ("!%~1:~0,1!") do (
if "%%A" neq "=" if "!$write.problemChars:%%A=!" equ "!$write.problemChars!" set "$write.special="
)
if not defined $write.special (
<nul set /p "=!%~1!"
exit /b
)
>"%$write.temp%_1.txt" (echo !str!!$write.sub!)
copy "%$write.temp%_1.txt" /a "%$write.temp%_2.txt" /b >nul
type "%$write.temp%_2.txt"
del "%$write.temp%_1.txt" "%$write.temp%_2.txt"
set "str2=!str:*%$write.sub%=%$write.sub%!"
if "!str2!" neq "!str!" <nul set /p "=!str2!"
exit /b
:writeInitialize
::
:: Defines 3 variables needed by the :write and :writeVar routines
::
:: $write.temp - specifies a base path for temporary files
::
:: $write.sub - contains the SUB character, also known as <CTRL-Z> or 0x1A
::
:: $write.problemChars - list of characters that cause problems for SET /P
:: <carriageReturn> <formFeed> <space> <tab> <0xFF> <equal> <quote>
:: Note that <lineFeed> and <equal> also causes problems, but are handled elsewhere
::
set "$write.temp=%temp%\writeTemp%random%"
copy nul "%$write.temp%.txt" /a >nul
for /f "usebackq" %%A in ("%$write.temp%.txt") do set "$write.sub=%%A"
del "%$write.temp%.txt"
for /f %%A in ('copy /z "%~f0" nul') do for /f %%B in ('cls') do (
set "$write.problemChars=%%A%%B ""
REM the characters after %%B above should be <space> <tab> <0xFF>
)
exit /b
【讨论】:
很高兴看到可以处理所有字符的非常强大的解决方案 我想指出的是,如果计算机恰好有网络连接到互联网,那么大约有这么多的批处理代码可以用来在计算机上下载和安装 python 或其他任何可以让你摆脱批次。批处理很有趣,但它的字符串功能最适合周末挑战。 @dbenham 在第 6 行 "echo(" 在功能上与 "echo." 相同 - 以前没见过。 @SkipR - 是的,它在功能上与ECHO.
、except ECHO.
can fail under obscure circumstances 相同。还有许多其他形式也可能在晦涩难懂的情况下失败。唯一始终有效的是ECHO(
。【参考方案18】:
您可以使用 gnuwin32(coreutils 包)中的“tr”删除换行符
@echo off
set L=First line
echo %L% | tr -d "\r\n"
echo Second line
pause
顺便说一句,如果您正在编写大量脚本,gnuwin32 是一座金矿。
【讨论】:
我也建议install git bash。确保它与 gnuwin32 不同(它是一个金矿,因此 +1),它只是一个不错的设置,并且几乎所有地方都有 git-bash 鼠标右键,包括开始菜单按钮。 你可以使用 tr 来删除最后一个空格字符,就像在trim
中一样?
使用 sed 进行修剪:sed -e "s/ *$//"
@panny - 我找不到名为 trim 的 posix/linux 实用程序。此外,\r
、\n
或 \r\n
(分别在 OSX、Posix 和 Windows 中的新行)不是“空格”字符。【参考方案19】:
使用:echo | set /p=
或 <NUL set /p=
都可以抑制换行符。
但是,当检查 ERRORLEVEL 变得很重要时编写更高级的脚本时,这可能非常危险,因为在不指定变量名的情况下设置 set /p=
会将 ERRORLEVEL 设置为 1。
更好的方法是只使用一个虚拟变量名称,如下所示:echo | set /p dummyName=Hello World
这将准确地产生你想要的东西,而不会在后台发生任何鬼鬼祟祟的事情,因为我不得不找出困难的方法,但这仅适用于管道版本; <NUL set /p dummyName=Hello
仍会将 ERRORLEVEL 提高到 1。
【讨论】:
警告:此命令会将 ERRORLEVEL 设置为 0。如果 ERRORLEVEL 大于 0,则会将 ERRORLEVEL 更改为 0。这在编写更高级的脚本时也可能很危险。 (但 +1 回答) 所以你基本上需要一个 IF ERRORLEVEL==0 (...) ELSE (...) 只是为了在这些情况下不损害你的环境。嘘。 好吧,编写更高级的批处理脚本本身已经很危险了:) 如果不是为了稳定执行,至少对作者的精神状态有风险【参考方案20】:我相信没有这样的选择。或者你可以试试这个
set text=Hello
set text=%text% world
echo %text%
【讨论】:
这仍然会打印一个换行符。 您可以根据需要连接同一个变量,并且只在最后回显。 在执行循环时或最后打印它并不重要,如果数据被保留。对于每个循环,您只需连接数据,然后在循环完成时打印它。结果是一样的。 它确实是否是循环进展的指标。 您从未在您的问题中声明或在您的问题的任何地方要求此行为。以上是关于Windows 批处理:没有换行的回显的主要内容,如果未能解决你的问题,请参考以下文章
从 Windows 批处理 (.bat) 脚本中回显带有 Unix 行尾的文本