DOS: ECHO text to previous line - by Paul Tomasi

AID: 1237
  • Status: Published

11250 points

  • Byt0t0
  • TypeTips/Tricks
  • Posted on2009-07-23 at 12:59:16
Awards
  • Community Pick
  • Experts Exchange Approved
One of my most closely kept secrets is revealed in this discussion

How to output text on the same line


This question was recently posted in EE by Simon336697

Consider the problem:

ECHO Hello
ECHO World
                                    
1:
2:

Select allOpen in new window



This would output the following to the screen:

    Hello
    World

However, what if we wanted the words Hello and World to appear on the same line as in:

    Hello World

This could be done as follows:

ECHO Hello World
                                    
1:

Select allOpen in new window



But this discussion is not about that. This discussion explores the possibility of outputting text to the previous line.


Now consider the following:

    output text to screen
    process other commands
    output more text to the same line

Impossible? Read on....


Firstly, let's use Simon336697's question as an example:

    1)  output "Searching...." to screen
    2)  PING
    3)  output (append) result to the same line

Before we continue, let's refine these instructions:

 1   )  output "Searching for %Computer%.... " to screen
 2   )  PING %Computer% >NUL 2>&1
 3.1)  if ping fails...
 3.2)     output "FAIL" to previous line
 3.3)  otherwise...
 3,4)     output "SUCCESS" to previous line
 3.5)  end-if

""][Ed Note]: The 2>&1 portion simply redirects STDERR to STDOUT.  
Thus, the sequence >NULL 2>&1 totally silences the PING command.


And, this is what the code would look like in a DOS batch file:

ECHO Searching for %Computer%.... 

PING %Computer% >NUL 2>&1

IF ERRORLEVEL 1 (
   ECHO FAIL
) ELSE (
   ECHO SUCCESS
)
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:

Select allOpen in new window



However, in the case of a successful PING, the output would still be as follows:

    Searching....
    SUCCESS

To enable ECHOing to the previous line then, the following syntax is used to suppress the cursor:

SET /P Var=text<NUL
                                    
1:

Select allOpen in new window


where Var is any variablename and text is the text output to the screen.


Normally, SET /P Var=text takes it's input from STDIN, the standard input device. This is usually the keyboard.

Rather than SET /P= accepting input from STDIN, we can force it to accept input from another device, in this case, the NUL device. This is done by redirecting output from NUL to SET /P= however, because NUL does not produce any output, SET /P= waits until it receives input, in this case, from the ECHO command.

So, with only a minor change to our program, this would now look something like the following:

SET /P var=Searching for %Computer%....<NUL

PING %Computer% >NUL 2>&1

IF ERRORLEVEL 1 (
   ECHO FAIL
) ELSE (
   ECHO SUCCESS
)
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:

Select allOpen in new window



And this time, in the case of a successful PING, the output is as follows:

    Searching for PC1....SUCCESS

where the variable %Computer% is set to PC1.

Finally, notice how PING's output is redirected to NUL. This is to ensure any output it produces is not sent to STDOUT, the standard output device, as SET /P= would capture this instead of capturing output from the ECHO command.
.
Asked On
2009-07-23 at 12:59:16ID1237
Tags

DOS ECHO "previous line" "same line" "batch file" "Paul Tomasi"

Topic

MS DOS

Views
8512

Comments

Expert Comment

by: Simon336697 on 2009-07-29 at 14:29:37ID: 2403

t0t0, that is so helpful thanks so much for this :>)

Expert Comment

by: dragon-it on 2009-07-29 at 23:16:46ID: 2417

Cool!  Never knew that one, thanks Paul..... noted.

You can extend that too then using set /p to print the "second" line and therefore keeping adding as you like... I can't seem to get PING to return an errorlevel for failed pings for me for some reason but you could keep some kind of progress counter while a process runs:

@echo off
mode con: cols=40 lines=4
color 4f
title Please Wait
echo                    0                100
SET /P var=Progress counter : <NUL

set count=0
:loop
  PING -n 2 127.0.0.1 >NUL 2>&1
  call :printline .
  set /a count=count+1
  if %count%==20 goto finish
goto loop

:printline
 REM Print text passed to sub without a carriage return.
 REM Sets line variable in case %1 intereferes with redirect
 set line=%1
 set /p var=%line%<NUL
exit /b

:finish
cls
color 0f
title Finished
mode con: cols=80 lines=25
echo Thankyou, all done now.
pause
exit /b

Expert Comment

by: Qlemo on 2009-10-21 at 16:22:35ID: 4631

Steve,
that is how Paul used it, or at least at the first occurence in a question I have seen - as a progress indicator. It is a good idea, and I have adopted it since then on several occasions ;-) I too have never seen it before Paul introduced (invented?) it.
About the ping issue: It seems as ping returns an errorlevel starting with XP.

Simon,
Did you vote "Yes"? If not, please do so, it is important for article authors to get that voting feedback!

Author Comment

by: t0t0 on 2009-10-22 at 01:14:52ID: 4643

Thank you qlemo for your thoughtful comments....

Expert Comment

by: AmazingTech on 2010-03-17 at 07:30:50ID: 10961

Great tip t0t0!

I would just add @ECHO OFF to the first line of your code for all the newbies out there.

Author Comment

by: t0t0 on 2010-03-17 at 09:03:44ID: 10976

Thank you AmazingTech.

As you know, I've always had a high regard for you and as ever, your suggestion is very welcome.... and of course, very appropriate where newbies are concerned.

Author Comment

by: t0t0 on 2010-07-21 at 14:10:29ID: 17318

Thank you Dan...

Expert Comment

by: x66_x72_x65_x65 on 2010-08-13 at 14:07:48ID: 18181

Very nice.  I wasn't aware of this.  Here is a modified example which incorporates multiple instances.

<b>Please Wait.........</b> with a second delay between each period.

Good for progress indicator, etc.  :)

I used to return to the previous line using ANSI escape sequences.  Really cool to see this in use without requiring ANSI driver.
@echo off
set /p a=Please wait<nul
set b=1
:loop
set /p a=.<nul
choice /t 1 /c y /d y>nul
set /a b=%b%+1
if %b%==10 goto :eof
goto :loop

                                        
1:
2:
3:
4:
5:
6:
7:
8:
9:

Select allOpen in new window

Expert Comment

by: x66_x72_x65_x65 on 2010-08-13 at 14:26:08ID: 18182

Here is a install progress example using ascii characters ... kinda fun to play around with.

Expert Comment

by: kdyer on 2010-09-26 at 21:51:44ID: 19928

I think this can be done even simpler..  Even back to the original post: "Being on one line."

HTH,

Kent
ECHO Hello
ECHO World


ECHO Hello & ECHO World

pause

                                        
1:
2:
3:
4:
5:
6:
7:

Select allOpen in new window

Expert Comment

by: dragon-it on 2010-09-27 at 00:54:51ID: 19937

Kent - I think paul's point here was this is a way of printing to the screen without a carriage return in the OUTPUT not in the batch file.

Steve

Author Comment

by: t0t0 on 2010-09-27 at 02:05:49ID: 19951

kdyer

You have not grasped the essence of this article. Look at the following code VERY carefully and try to understand what it is I am achieving with the 'SET /P' and '<NUL' command.


    SET /P var=Searching for %Computer%....<NUL

    PING %Computer% >NUL 2>&1

    IF ERRORLEVEL 1 (
       ECHO FAIL
    ) ELSE (
       ECHO SUCCESS
    )


The only other way (well, one such possible way) you could do this is:


    PING %Computer% >NUL 2>&1

    IF ERRORLEVEL 1 (
       ECHO Searching for %Computer%....FAIL
    ) ELSE (
       ECHO Searching for %Computer%....SUCCESS
    )


But that would not be correct because quite clearly, by the time we get to the IF statement, we have ALREADY 'searched' using PING. so the message "Searching for %Computer%...." ("FAIL" or "SUCCESS")  is out of context with the code.

If none of this makes sense to you then try this simple program to see what effect it produces:


    FOR /L %%a IN (0,1,9) DO (
        SET /P .=%%a <NUL
    )


As opposed to this:


    FOR /L %%a IN (0,1,9) DO (
        ECHO %%a
    )

Expert Comment

by: QCubed on 2011-01-18 at 15:03:50ID: 22943

Very Nice find t0t0! =)

Expert Comment

by: x66_x72_x65_x65 on 2011-08-09 at 14:05:21ID: 30563

I found out by using this method we can strip carriage returns when outputting to files... when creating a flat csv file for example.

Example:
 
@echo off
for /f "delims=?" %%f in ('dir/s/ad/b/on 2^>^>error.log') do (
	set /p dir=%%f;<nul>>list.csv
)
                                        
1:
2:
3:
4:

Select allOpen in new window

Expert Comment

by: dragon-it on 2011-08-09 at 16:42:11ID: 30574

Nice idea.  You can do it without having to do the >> append for each line too by redirecting the whole for command into a file once:

@echo off
(for /f "delims=?" %%f in ('dir/s/ad/b/on 2^>^>error.log') do (
        set /p dir=%%f;<nul
))>list.csv

Steve

Expert Comment

by: x66_x72_x65_x65 on 2011-08-09 at 17:27:57ID: 30575

@Steve, wow... learned something new!  I didn't know you could do that... :)

Expert Comment

by: paultomasi on 2011-08-09 at 19:28:30ID: 30579

Hey, hiya x66_x72_x65_x65

Nice to receive feedback occasionally...

SET /P with <NUL suppresses the carriage-return/Linefeed characters. As you've discovered, and as one would expect, this also works when redirecting output.

By the way, I don't think you need to redirect STDERR to error.log as DIR /A:D will always be true even if there are no subdirectories (not absolutely sure for the root directory though so please don't shoot me down over this).

Also check out the following command:

   (FOR /R . %%f IN (.) DO SET /P .=%%~Ff<NUL)>list.csv

Hope that's useful for ya.

Expert Comment

by: x66_x72_x65_x65 on 2011-08-16 at 09:20:19ID: 30741

@paultomasi:Thanks for the feedback and example code.  An STDERR condition exists whenever the maximum directory/file length is encountered.  The purpose of the STDERR redirect is to create a clean .csv without the possibility of any embedded error messages.

Expert Comment

by: pony10us on 2012-02-16 at 09:05:51ID: 43066

I just stumbled across this article.  There was a question just the other day that I was following.  I will certainly make use of this in some of my batch files.   :)

Thank you t0t0 and all contributors.

Expert Comment

by: paultomasi on 2012-02-21 at 15:26:06ID: 43493

No probs...

BTW, since writing this article, I discovered you don't need an Lvalue so:

    set /p .=<nul

can also be written as:

    set /p =<nul

(I use a full-stop, or period, as an example but it could just as well be any allowable identifier)

Expert Comment

by: dragon-it on 2012-02-21 at 16:19:38ID: 43495

I have used this method too in the past to make it more obvious (ish):

SET PRINT=^<NUL set /p =

Then in the area needed you can do:

%PRINT% What I want to print

or

SET echox=^<NUL set /p =
%echox% mytext

etc.

Steve

Expert Comment

by: Qlemo on 2012-02-22 at 02:23:48ID: 43520

Just to throw in another variant:
doskey echox=^<nul set /p=$*
                                        
1:

Select allOpen in new window


and you can use echox everywhere in the current shell. Looks better than %echox%, IMO.

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top MS DOS Experts

  1. billprew

    140,280

    Master

    0 points yesterday

    Profile
    Rank: Genius
  2. paultomasi

    49,157

    10 points yesterday

    Profile
    Rank: Master
  3. dragon-it

    35,867

    0 points yesterday

    Profile
    Rank: Genius
  4. oBdA

    30,202

    0 points yesterday

    Profile
    Rank: Savant
  5. gerwinjansen

    25,227

    0 points yesterday

    Profile
    Rank: Sage
  6. ReneGe

    24,598

    0 points yesterday

    Profile
    Rank: Guru
  7. QCubed

    23,732

    0 points yesterday

    Profile
    Rank: Guru
  8. Bartender_1

    11,800

    0 points yesterday

    Profile
    Rank: Sage
  9. RobSampson

    10,800

    0 points yesterday

    Profile
    Rank: Genius
  10. Qlemo

    10,191

    0 points yesterday

    Profile
    Rank: Genius
  11. BillDL

    8,800

    0 points yesterday

    Profile
    Rank: Genius
  12. lionelmm

    7,446

    0 points yesterday

    Profile
    Rank: Master
  13. DaveBaldwin

    7,136

    0 points yesterday

    Profile
    Rank: Genius
  14. l33tf0b

    6,600

    0 points yesterday

    Profile
    Rank: Wizard
  15. sirbounty

    6,400

    0 points yesterday

    Profile
    Rank: Genius
  16. leew

    6,320

    0 points yesterday

    Profile
    Rank: Savant
  17. pony10us

    5,000

    0 points yesterday

    Profile
    Rank: Wizard
  18. ve3ofa

    4,552

    0 points yesterday

    Profile
    Rank: Genius
  19. ltlbearand3

    4,300

    0 points yesterday

    Profile
    Rank: Wizard
  20. TazDevil1674

    4,300

    0 points yesterday

    Profile
    Rank: Master
  21. Run5k

    4,196

    0 points yesterday

    Profile
    Rank: Genius
  22. DTHConsulting

    4,186

    0 points yesterday

    Profile
    Rank: Guru
  23. serialband

    4,000

    0 points yesterday

    Profile
    Rank: Master
  24. Anuroopsundd

    4,000

    0 points yesterday

    Profile
    Rank: Sage
  25. thinkpads_user

    3,750

    0 points yesterday

    Profile
    Rank: Genius

Hall Of Fame