简体   繁体   中英

Windows batch: echo without new line

What is the Windows batch equivalent of the Linux shell command echo -n which suppresses the newline at the end of the output?

The idea is to write on the same line inside a loop.

Using set and the /p parameter you can echo without newline:

C:\> echo Hello World
Hello World

C:\> echo|set /p="Hello World"
Hello World
C:\>

Source

Using: echo | set /p= echo | set /p= or <NUL set /p= will both work to suppress the newline.

However, this can be very dangerous when writing more advanced scripts when checking the ERRORLEVEL becomes important as setting set /p= without specifying a variable name will set the ERRORLEVEL to 1.

A better approach would be to just use a dummy variable name like so:
echo | set /p dummyName=Hello World

This will produce exactly what you want without any sneaky stuff going on in the background as I had to find out the hard way, but this only works with the piped version; <NUL set /p dummyName=Hello will still raise the ERRORLEVEL to 1.

The simple SET /P method has limitations that vary slightly between Windows versions.

  • Leading quotes may be stripped

  • Leading white space may be stripped

  • Leading = causes a syntax error.

See http://www.dostips.com/forum/viewtopic.php?f=3&t=4209 for more information.

jeb posted a clever solution that solves most of the problems at Output text without linefeed, even with leading space or = I've refined the method so that it can safely print absolutely any valid batch string without the new line, on any version of Windows from XP onward. Note that the :writeInitialize method contains a string literal that may not post well to the site. A remark is included that describes what the character sequence should be.

The :write and :writeVar methods are optimized such that only strings containing troublesome leading characters are written using my modified version of jeb's COPY method. Non-troublesome strings are written using the simpler and faster SET /P method.

@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

As an addendum to @xmechanix's answer, I noticed through writing the contents to a file:

echo | set /p dummyName=Hello World > somefile.txt

That this will add an extra space at the end of the printed string , which can be inconvenient, specially since we're trying to avoid adding a new line (another whitespace character) to the end of the string.

Fortunately, quoting the string to be printed, ie using:

echo | set /p dummyName="Hello World" > somefile.txt

Will print the string without any newline or space character at the end.

A solution for the stripped white space in SET /P:

the trick is that backspace char which you can summon in the text editor EDIT for DOS. To create it in EDIT press ctrlP+ctrlH . I would paste it here but this webpage can't display it. It's visible on Notepad though (it's werid, like a small black rectangle with a white circle in the center)

So you write this:

<nul set /p=.9    Hello everyone

The dot can be any char, it's only there to tell SET /P that the text starts there, before the spaces, and not at the " Hello ". The " 9 " is a representation of the backspace char that I can't display here. You have to put it instead of the 9, and it will delete the " . " , after which you'll get this:

    Hello Everyone

instead of:

Hello Everyone

I hope it helps

You can remove the newline using "tr" from gnuwin32 ( coreutils package)

@echo off
set L=First line
echo %L% | tr -d "\r\n"
echo Second line
pause

By the way, if you are doing lots of scripting, gnuwin32 is a goldmine.

Here is another method, it uses Powershell Write-Host which has a -NoNewLine parameter, combine that with start /b and it offers the same functionality from batch.

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

Output

Result 1 - Result 2 - Result 3 - Press any key to continue . . .

This one below is slightly different, doesn't work exactly like the OP wants, but is interesting because each result overwrites the previous result emulating a counter.

@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

DIY cw.exe (console write) utility

If you don't find it out-of-the-box, off-the-shelf, you can DIY. With this cw utility you can use every kind of characters. At least, I'd like to think so. Please stress-test it and let me know.

Tools

All you need is .NET installed, which is very common nowadays.

Materials

Some characters typed/copy-pasted.

Steps

  1. Create .bat file with the following content.
/* >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);
        }
    }
}
  1. Run it.

  2. Now you have a nice 4KB utility so you can delete the .bat .

Alternatively, you can insert this code as a subroutine in any batch, send the resulting .exe to %temp% , use it in your batch and delete it when you're done.

How to use

If you want write something without new line:
cw Whatever you want, even with "", but remember to escape ^|, ^^, ^&, etc. unless double-quoted, like in "| ^ &".

If you want a carriage return (going to the beginning of the line), run just
cw

So try this from command line:

for /l %a in (1,1,1000) do @(cw ^|&cw&cw /&cw&cw -&cw&cw \&cw)

I made a function out of @arnep 's idea:

echo|set /p="Hello World"

here it is:

:SL (sameline)
echo|set /p=%1
exit /b

Use it with call :SL "Hello There"
I know this is nothing special but it took me so long to think of it I figured I'd post it here.

From here

<nul set /p =Testing testing

and also to echo beginning with spaces use

echo.Message goes here

Maybe this is what your looking for, it's a old school script... :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

or maybe your trying to replace a current line instead of writing to a new line? you can experiment with this by removing the "%bs%" after the "." sign and also by spacing out the other "%bs%" after the "Example message".

for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "bs=%%a"
<nul set /p=.%bs%         Example message         %bs%
pause

I find this really interesting because it uses a variable for a purpose other than what it is intended to do. as you can see the "%bs%" represents a backspace. The second "%bs%" uses the backspace to add spaces after the "Example message" to separate the "Pause command's output" without actually adding a visible character after the "Example message". However, this is also possible with a regular percentage sign.

Sample 1: This works and produces Exit code = 0. That is Good. Note the "." , directly after echo.

C:\\Users\\phife.dog\\gitrepos\\1\\repo_abc\\scripts #
@echo.| set /p JUNK_VAR=This is a message displayed like Linux echo -n would display it ... & echo %ERRORLEVEL%

This is a message displayed like Linux echo -n would display it ... 0

Sample 2: This works but produces Exit code = 1. That is Bad. Please note the lack of ".", after echo. That appears to be the difference.

C:\\Users\\phife.dog\\gitrepos\\1\\repo_abc\\scripts #
@echo | set /p JUNK_VAR=This is a message displayed like Linux echo -n would display it ... & echo %ERRORLEVEL%

This is a message displayed like Linux echo -n would display it ... 1

Inspired by the answers to this question, I made a simple counter batch script that keeps printing the progress value (0-100%) on the same line (overwritting the previous one). Maybe this will also be valuable to others looking for a similar solution.

Remark : The * are non-printable characters, these should be entered using [ Alt + Numpad 0 + Numpad 8 ] key combination, which is the backspace character.

@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

You can suppress the new line by using the set /p command. The set /p command does not recognize a space, for that you can use a dot and a backspace character to make it recognize it. You can also use a variable as a memory and store what you want to print in it, so that you can print the variable instead of the sentence. For example:

@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

In this way you can print anything without a new line. I have made the program to print the characters one by one, but you can use words too instead of characters by changing the loop.

In the above example I used "enabledelayedexpansion" so the set /p command does not recognize "!" character and prints a dot instead of that. I hope that you don't have the use of the exclamation mark "!" ;)

Use EchoX.EXE from the terrific "Shell Scripting Toolkit" by Bill Stewart
How to suppress the linefeed in a Windows Cmd script:

@Echo Off
Rem Print three Echos in one line of output
EchoX -n "Part 1 - "
EchoX -n "Part 2 - "
EchoX    "Part 3"
Rem

gives:

Part 1 - Part 2 - Part 3
{empty line}
d:\Prompt>

The help for this usage is:

Usage: echox [-n] message
  -n       Do not skip to the next line.
  message  The text to be displayed.

The utility is smaller than 48K, and should live in your Path. More things it can do:
- print text without moving to the next line
- print text justified to the left, center, or right, within a certain width
- print text with Tabs, Linefeeds, and Returns
- print text in foreground and background colors

The Toolkit includes twelve more great scripting tricks.
The download page also hosts three other useful tool packages.

方法如下: <nul set /p="Your Text"

Echo with preceding space and without newline

As stated by Pedro earlier, echo without new line and with preceding space works (provided "9" is a true [BackSpace]).

<nul set /p=.9    Hello everyone

I had some issues getting it to work in Windows 10 with the new console but managed the following way.
In CMD type:

echo .◘>bs.txt

I got "◘" by pressing [Alt] + [8]
(the actual symbol may vary depending upon codepage).

Then it's easy to copy the result from "bs.txt" using Notepad.exe to where it's needed.

@echo off
<nul set /p "_s=.◘    Hello everyone"
echo: here

With 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));

if it is called write.bat you can test it like:

call write.bat string & echo _Another_String_

If you want to use powershell but with cmd defined variables you can use:

set str=_My_StrinG_
powershell "Write-Host -NoNewline ""%str%""""  & echo #Another#STRING#

I found this simple one-line batch file called "EchoPart.bat" to be quite useful.

@echo | set /p=%*

I could then write something like the line below even on an interactive CMD line, or as part of a shortcut. It opens up a few new possibilities.

echopart "Hello, " & echopart "and then " & echo Goodbye

在此处输入图片说明

And if you're using it in batch files, the texts can be got from parameter variables instead of immutable strings. For instance:

@echopart Hello %* & @echo , how are you?

So that executing this line in "SayHello.bat" allows:

在此处输入图片说明

or even...

在此处输入图片说明

Have a play, and have fun!

I believe there's no such option. Alternatively you can try this

set text=Hello
set text=%text% world
echo %text%

Late answer here, but for anyone who needs to write special characters to a single line who find dbenham 's answer to be about 80 lines too long and whose scripts may break (perhaps due to user-input) under the limitations of simply using set /p , it's probably easiest to just to pair your .bat or .cmd with a compiled C++ or C-language executable and then just cout or printf the characters. This will also allow you to easily write multiple times to one line if you're showing a sort of progress bar or something using characters, as OP apparently was.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM