Windows equivalent of "echo -n" no longer works in Win7 - windows

I had a nifty trick in Windows cmd.exe (at least up to XP) to emulate the behaviour of the UNIX echo without a newline, echo -n. For example, the command:
<nul: set /p junk= xyzzy
would result in exactly six characters being output, the leading space and the string "xyzzy", and nothing else.
If you're interested in why this works, it's actually an input command which outputs " xyzzy" as the prompt then waits for user input before assigning that input to the junk environment variable. In this particular case, it doesn't wait for user input since it grabs the input from the nul device.
It was rather useful in cmd scripts when (for example) processing files in a loop (one iteration per file) where you want to list more than one per line. By using this trick, you could simply output each file name followed by a space and no newline then, after the loop, output a newline to finish up:
Processing files:
file1.txt file42.txt p0rn.zip
Now I discover that, under Windows 7, the spaces are no longer output so what I get is:
Processing files:
file1.txtfile42.txtp0rn.zip
Is there a way I can get set /p to start honouring my spaces again, or is there another way in Win7 to achieve the same effect?
I've tried quoting, using . (which works in echo) and even escaping the string with ^, but none of them seem to work:
C:\Pax> <nul: set /p junk= xyzzy
xyzzy
C:\Pax> <nul: set /p junk=" xyzzy"
xyzzy
C:\Pax> <nul: set /p junk=' xyzzy'
' xyzzy'
C:\Pax> <nul: set /p junk=. xyzzy
. xyzzy
C:\Pax> <nul: set /p junk=^ xyzzy
xyzzy
What I need is:
C:\Pax> some_magical_command_with_an_argument xyzzy
xyzzy
which will give me the space(s) at the start and no newline at the end.

This is very similar to paxdiablo's answer, except I use a hybrid JScript/batch file instead of a temporary VBScript file.
My script is called jEval.bat - and it simply evaluates any valid JScript expression and writes the result to stdout, optionally with a trailing newline. The silly little script is extremely useful for batch programming.
Assuming jEval.bat is either in your current folder, or somewhere in your PATH, then you can simply do something like:
call jeval "' xyzzy'"
Here is the script. It really is very simple. Most of the code is related to documentation, error handling, and a built in help system.
#if (#X)==(#Y) #end /* harmless hybrid line that begins a JScrpt comment
::************ Documentation ***********
:::
:::jEval JScriptExpression [/N]
:::jEval /?
:::
::: Evaluates a JScript expression and writes the result to stdout.
:::
::: A newline (CR/LF) is not appended to the result unless the /N
::: option is used.
:::
::: The JScript expression should be enclosed in double quotes.
:::
::: JScript string literals within the expression should be enclosed
::: in single quotes.
:::
::: Example:
:::
::: call jEval "'5/4 = ' + 5/4"
:::
::: Output:
:::
::: 5/4 = 1.25
:::
::************ Batch portion ***********
#echo off
if "%~1" equ "" (
call :err "Insufficient arguments"
exit /b
)
if "%~2" neq "" if /i "%~2" neq "/N" (
call :err "Invalid option"
exit /b
)
if "%~1" equ "/?" (
setlocal enableDelayedExpansion
for /f "delims=" %%A in ('findstr "^:::" "%~f0"') do (
set "ln=%%A"
echo(!ln:~3!
)
exit /b
)
cscript //E:JScript //nologo "%~f0" %*
exit /b
:err
>&2 echo ERROR: %~1. Use jeval /? to get help.
exit /b 1
************ JScript portion ***********/
if (WScript.Arguments.Named.Exists("n")) {
WScript.StdOut.WriteLine(eval(WScript.Arguments.Unnamed(0)));
} else {
WScript.StdOut.Write(eval(WScript.Arguments.Unnamed(0)));
}

This isn't using set or other cmd-internal stuff, but you can use cscript (also included in a standard Windows install) to do a similar thing. You can even control it from the cmd file itself (no separate files to maintain) by use of creating temporary vbs files.
Place this code in your cmd file:
rem Create the VBS file to output spaces and a word.
echo.for i = 1 to WScript.Arguments.Item(0) >spacetext.vbs
echo. WScript.StdOut.Write ^" ^" >>spacetext.vbs
echo.next >>spacetext.vbs
echo.WScript.StdOut.Write WScript.Arguments.Item(1) >>spacetext.vbs
rem Do this once per word you want output (eg, in a loop).
cscript /nologo spacetext.vbs 0 Hello,
cscript /nologo spacetext.vbs 1 my
cscript /nologo spacetext.vbs 1 name
cscript /nologo spacetext.vbs 1 is
cscript /nologo spacetext.vbs 4 Pax.
rem Do this at the end to add newline and kill temp file.
echo.
del spacetext.vbs
The output of this is what you would expect:
Hello, my name is Pax.

You mean like this?
#ECHO OFF
SETLOCAL
FOR /l %%i IN (1,1,4) DO <NUL SET /p var="item %%i "
Result:
item 1 item 2 item 3 item 4
Or do you absolutely insist on a space at the start?

OK, have the right answer now: you can't have a leading <space> in Win7 with set /p. There are differences between Windows versions:
Syntax | XP | Vista and Windows 7
----------------------+-------------------------------------+-------------------------------------
<nul set /p =!msg! |- If 1st char is quote, then trims |- Trims leading white space chars.
or | that quote, and if at least one |- If 1st non white space char is
<nul set /p "=!msg!" | additional quote, than trims last | quote, then that quote is treated
| quote and all remaining chars. | as white space and trimmed, and if
|- If 1st non trimmed char is =, then | at least one additional quote, then
| syntax error. | trims last quote and all remaining
| | chars.
| |- If 1st non trimmed char is =, then
| | syntax error.
----------------------+-------------------------------------+-------------------------------------
<nul set /p ="!msg!" |- Trims leading control chars and |- Trims leading white space chars.
or | spaces. |- If 1st non trimmed char is =, then
<nul set /p "="!msg!""|- If 1st non trimmed char is =, then | syntax error.
| syntax error. |
----------------------+-------------------------------------+-------------------------------------
On Vista and Windows 7, the trimmed leading white space chars are:
9 0x09 Horizontal Tab
10 0x0A New Line
11 0x0B Vertical Tab
12 0x0C Form Feed
13 0x0D Carriage Return
32 0x20 Space
255 0xFF Non-breaking Space
source
For an other technique to get leading spaces in pure batch see here

Related

Prevent batch script from terminating upon invalid character input

I always have this issue when writing batch scripts. Whenever I have the script prompt the user to set a variable, if a semicolon (that's just one example) is inputted, the script will close. Is there a way to prevent it from doing so?
Example:
#echo off
:1
cls
echo Please enter your ID:
set /P id=
if /i %id%==119 goto Tom
if /i %id%==204 goto Brittany
if /i %id%==12 goto Shannon
if /i %id%==64 goto Jack
goto 1
:Tom
cls
echo Tom, you have to mow the lawn.
pause>nul
exit
:Brittany
cls
echo Brittany, you have to fold the laundry.
pause>nul
exit
:Shannon
cls
echo Shannon, you have to feed the dog.
pause>nul
exit
:Jack
cls
echo Jack, you have to replace the radio's capacitors.
pause>nul
exit
What I would see running that script:
C:\>myscript.bat
Please enter your ID:
asjfash;dfjlas;ldf
asjfash;dfjlas;ldf==i was unexpected at this time.
and the script closes.
Thanks!
Read Syntax : Escape Characters, Delimiters and Quotes:
Delimiters
Delimiters separate one parameter from the next - they split the
command line up into words.
Parameters are most often separated by spaces, but any of the
following are also valid delimiters:
Comma (,)
Semicolon (;)
Equals (=)
Space ()
Tab (   )
If a user inputs some string containing any of above listed separators (like set "id=1 19" then %id% contains a space), then
if /i %id%==119 goto Tom
results to
if /i 1 19==119 goto Tom
↑ this space causes error 19==119 was unexpected at this time
Definitely, you need to escape delimiters and all other cmd-poisonous characters as follows:
#echo off
:1
cls
echo Please enter your ID:
set /P id=
if /i "%id%"=="119" goto Tom
if /i "%id%"=="204" goto Brittany
if /i "%id%"=="12" goto Shannon
if /i "%id%"=="64" goto Jack
goto 1
rem script continues here
FYI, Redirection article lists other cmd-poisonous characters which need to be escaped as their unescaped occurrence in a batch script has following meaning:
&  - Single Ampersand: used as a command separator
&& - Double Ampersand: conditional command separator (like if errorlevel 0)
|| - Double Pipe (Vertical Line): conditional command separator (like if errorlevel 1)
|  - Single Pipe: redirects the std.output of one command into the std.input of another
>  - Single Greater Than: redirects output to either a file or file like device
>> - Double Greater than: output will be added to the very end of the file
<  - Less Than: redirect the contents of a file to the std.input of a command

Is it possible to echo some non-printable characters in batch/cmd?

motivation
I have a 3rd party, somehow long .bat file written for some specific function and would take considerable effort to re-write (which effort is also hindered by my problem). In for loops the most basic way to debug it would seem echoing some information to the screen. I used to do this with \r (0x0D) character in other languages that on some terminals/console re-writes the same line (to avoid overflooding, since in my case the last line would contain the error). I already save the value to a variable. However, since iteration might take quite long, I'd still be happy to write some output to the screen that won't overflood.
what I've tried
I know I can echo a single newline in cmd with echo. - however I need only the carriage return
I've tried these but they did't work: echo \r, echo ^r, echo \x0d, echo ^x0d, echo #0d, echo ^#0d, echo #x0d, echo ^x0d
I've tried to duck the net for similar stuff without much help
question
Is it possible to somehow echo a carriage-return (or other non-printable) character in a windows/dos/nt/cmd batch file?
ps. I use the XP or the 7 cmd processor
You need two hacks - one to define a carriage return character, and another to echo a line of text without issuing the newline character.
1) Define carriage return.
:: Define CR to contain a carriage return (0x0D)
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
Once defined, the value can only be accessed via delayed expansion - as in !CR!, not %CR%.
2) Print text to the screen without issuing a newline
<nul set /p "=Your message here"
This will fail if the string starts with a =.
Also, leading quotes and/or white space may be stripped, depending on the Windows version
Putting it all together
#echo off
setlocal enableDelayedExpansion
:: Define CR to contain a carriage return (0x0D)
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
<nul set/p"=Part 1 - press a key!CR!"
pause >nul
<nul set/p"=Part 2 - press a key!CR!"
pause >nul
<nul set/p"=Part 3 - Finished !CR!"
Note that I put the !CR! at the end of each message in preparation for the next. You cannot put the !CR! at the beginning because leading white space will be stripped.
Somewhere along the line, "echo\" works to print a [cr] line. Great for ending an output from some other command that doesn't put [cr] at the end.
I've used this for sending CR to files as in IPconfig | find "Reply" >>myip.txt and then echo\ >>myip.txt
Building on dbenham's post, I have the following routines that work in Win7 and mostly editable in Notepad; however, I used Scite to generate the backspace, ALT+008, character. It differs slightly by first clearing the row, and placing the cursor at the end of the text. Here are the routines:
:RECHO
<nul set/p"=backspace!CR!tabtabtabtabtabtabtabtabtabtab"
<nul set/p"=backspace!CR!%*"
GOTO :EOF
:NECHO
<nul set/p"=backspace!CR!tabtabtabtabtabtabtabtabtabtab"
ECHO backspace!CR!%*
GOTO :EOF
dbenham's example modified:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
FOR /F %%a IN ('copy /Z "%~dpf0" nul') DO SET "CR=%%a"
SET "BS="
ECHO Testing CR. This line a regular echo ...
CALL :RECHO Part 1 - press a key
pause >nul
CALL :RECHO Part 2 - press a key
pause >nul
CALL :NECHO Part 3 - Finished
ECHO Testing CR. This line a regular echo ...
GOTO END
:RECHO
<nul set/p"=!BS!!CR! "
<nul set/p"=!BS!!CR!%*"
GOTO :EOF
:NECHO
<nul set/p"=!BS!!CR! "
ECHO !BS!!CR!%*
GOTO :EOF
:END
ENDLOCAL
EXIT /B
When copying the above script, make sure the backspace character is preserved.
SET "BS=backspace"
Here's how I catch & echo 0x0A in cmd:
(
set n=^
)
Then to test:
echo Ila!n!you
echo Ila!n!!n!you
set /p="la!n!"<nul > newline
You may see the written file via hex viewer eg fc or comp
00000000: 00 6C
00000001: 00 61
00000002: 00 0A
Tested in Win 10 CMD

Remove trailing spaces from a file using Windows batch?

How could I trim all trailing spaces from a text file using the Windows command prompt?
The DosTips RTRIM function that Ben Hocking cites can be used to create a script that can right trim each line in a text file. However, the function is relatively slow.
DosTips user (and moderator) aGerman developed a very efficient right trim algorithm. He implemented the algorithm as a batch "macro" - an interesting concept of storing complex mini scripts in environment variables that can be executed from memory. The macros with arguments are a major discussion topic in and of themselves that is not relevent to this question.
I have extracted aGerman's algorithm and put it in the following batch script. The script expects the name of a text file as the only parameter and proceeds to right trim the spaces off each line in the file.
#echo off
setlocal enableDelayedExpansion
set "spcs= "
for /l %%n in (1 1 12) do set "spcs=!spcs!!spcs!"
findstr /n "^" "%~1" >"%~1.tmp"
setlocal disableDelayedExpansion
(
for /f "usebackq delims=" %%L in ("%~1.tmp") do (
set "ln=%%L"
setlocal enableDelayedExpansion
set "ln=!ln:*:=!"
set /a "n=4096"
for /l %%i in (1 1 13) do (
if defined ln for %%n in (!n!) do (
if "!ln:~-%%n!"=="!spcs:~-%%n!" set "ln=!ln:~0,-%%n!"
set /a "n/=2"
)
)
echo(!ln!
endlocal
)
) >"%~1"
del "%~1.tmp" 2>nul
Assuming the script is called rtrimFile.bat, then it can be called from the command line as follows:
rtrimFile "fileName.txt"
A note about performance
The original DosTips rtrim function performs a linear search and defaults to trimming a maximum of 32 spaces. It has to iterate once per space.
aGerman's algorithm uses a binary search and it is able to trim the maximum string size allowed by batch (up to ~8k spaces) in 13 iterations.
Unfotunately, batch is very SLOW when it comes to processing text. Even with the efficient rtrim function, it takes ~70 seconds to trim a 1MB file on my machine. The problem is, just reading and writing the file without any modification takes significant time. This answer uses a FOR loop to read the file, coupled with FINDSTR to prefix each line with the line number so that blank lines are preserved. It toggles delayed expansion to prevent ! from being corrupted, and uses a search and replace operation to remove the line number prefix from each line. All that before it even begins to do the rtrim.
Performance could be nearly doubled by using an alternate file read mechanism that uses set /p. However, the set /p method is limited to ~1k bytes per line, and it strips trailing control characters from each line.
If you need to regularly trim large files, then even a doubling of performance is probably not adequate. Time to download (if possible) any one of many utilities that could process the file in the blink of an eye.
If you can't use non-native software, then you can try VBScript or JScript excecuted via the CSCRIPT batch command. Either one would be MUCH faster.
UPDATE - Fast solution with JREPL.BAT
JREPL.BAT is a regular expression find/replace utility that can very efficiently solve the problem. It is pure script (hybrid batch/JScript) that runs natively on any Windows machine from XP onward. No 3rd party exe files are needed.
With JREPL.BAT somewhere within your PATH, you can strip trailing spaces from file "test.txt" with this simple command:
jrepl " +$" "" /f test.txt /o -
If you put the command within a batch script, then you must precede the command with CALL:
call jrepl " +$" "" /f test.txt /o -
Go get yourself a copy of CygWin or the sed package from GnuWin32.
Then use that with the command:
sed "s/ *$//" inputFile >outputFile
Dos Tips has an implementation of RTrim that works for batch files:
:rTrim string char max -- strips white spaces (or other characters) from the end of a string
:: -- string [in,out] - string variable to be trimmed
:: -- char [in,opt] - character to be trimmed, default is space
:: -- max [in,opt] - maximum number of characters to be trimmed from the end, default is 32
:$created 20060101 :$changed 20080219 :$categories StringManipulation
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
call set string=%%%~1%%
set char=%~2
set max=%~3
if "%char%"=="" set char= &rem one space
if "%max%"=="" set max=32
for /l %%a in (1,1,%max%) do if "!string:~-1!"=="%char%" set string=!string:~0,-1!
( ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" SET %~1=%string%
)
EXIT /b
If you're not used to using functions in batch files, read this.
There is a nice trick to remove trailing spaces based on this answer of user Aacini; I modified it so that all other spaces occurring in the string are preserved. So here is the code:
#echo off
setlocal EnableDelayedExpansion
rem // This is the input string:
set "x= This is a text string containing many spaces. "
rem // Ensure there is at least one trailing space; then initialise auxiliary variables:
set "y=%x% " & set "wd=" & set "sp="
rem // Now here is the algorithm:
set "y=%y: =" & (if defined wd (set "y=!y!!sp!!wd!" & set "sp= ") else (set "sp=!sp! ")) & set "wd=%"
rem // Return messages:
echo input: "%x%"
echo output: "%y%"
endlocal
However, this approach fails when a character of the set ^, !, " occurs in the string.
Good tool for removing trailing spaces in files in windows:
http://mountwhite.net/en/spaces.html
I just found a very nice solution for trimming off white-spaces of a string:
Have you ever called a sub-routine using call and expanded all arguments using %*? You will notice that any leading and/or trailing white-spaces are removed. Any white-spaces occurring in between other characters are preserved; so are all the other command token separators ,, ;, = and also the non-break space (character code 0xFF). This effect I am going to utilise for my script:
#echo off
set "STR="
set /P STR="Enter string: "
rem /* Enable Delayed Expansion to avoid trouble with
rem special characters: `&`, `<`, `>`, `|`, `^` */
setlocal EnableDelayedExpansion
echo You entered: `!STR!`
call :TRIM !STR!
echo And trimmed: `!RES!`
endlocal
exit /B
:TRIM
set "RES=%*"
exit /B
This script expects a string entered by the user which is then trimmed. This can of course also be applied on lines of a file (which the original question is about, but reading such line by line using for /F is shown in other answers anyway, so I skip this herein). To trim the string on one side only, add a single character to the opposite side prior to trimming and remove it afterwards.
This approach has got some limitations though: it does not handle characters %, !, ^ and " properly. To overcome this, several intermediate string manipulation operations become required:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "STR="
set /P STR="Enter string: "
setlocal EnableDelayedExpansion
echo You entered: `!STR!`
set "STR=!STR:%%=%%%%!"
set "STR=!STR:"=""!^"
if not "%STR%"=="%STR:!=%" set "STR=!STR:^=^^^^!"
set "STR=%STR:!=^^^!%"
call :TRIM !STR!
set "RES=!RES:""="!^"
echo And trimmed: `!RES!`
endlocal
endlocal
exit /B
:TRIM
set "RES=%*"
exit /B
Update
Both of the above scripts cannot handle the characters &, <, > and |, because call seems to become aborted as soon as such a character appears in an unquoted and unescaped manner.
However, I finally found a way to fix that and come up with an approach that can successfully deal with all characters (except perhaps some control characters, which I did not test):
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem // The last white-space in `STRING` is a tabulator:
set "RESULT=" & set "STRING= (<&>"^|)^^!^^^^;,= ^"
echo Input string: `!STRING!`
rem // Double quotes to avoid troubles with unbalanced ones:
if defined STRING set "STRING=!STRING:"=""!^"
rem // Particularly handle carets and exclamation marks as delayed expansion is enabled:
if defined STRING set "STRING=!STRING:^=^^^^!"
if defined STRING set "STRING=%STRING:!=^^^!%" !
if defined STRING (
rem // Escape all characters that `call` has got troubles with:
set "STRING=!STRING:^=^^!"
set "STRING=!STRING:&=^&!"
set "STRING=!STRING:<=^<!"
set "STRING=!STRING:>=^>!"
set "STRING=!STRING:|=^|!"
)
rem /* Call the sub-routine here; the strigs `!=!` constitute undefined dummy variables
rem with an illegal name, which eventually become removed; the purpose of them us to
rem enable usage of that `call` inside of a `for` loop with the meta-variable `%%S`,
rem which would otherwise become unintentionally expanded rather than `%%STRING%%`,
rem which literally contained `%%S`; the `!=!` at the end is just there in case you
rem want to append another string that could also match another `for` meta-variable;
rem note that `!!` is not possible as this would be collapsed to a single `!`, so
rem a (most probably undefined) variable `!STRING%!` would then become expanded: */
call :TRIM %%!=!STRING%%!=!
rem /* The caret doubling done by `call` does not need to be reverted, because due to
rem doubling of the quotes carets appear unquoted, so implicit reversion occurs here;
rem of course the doubling of the quotes must eventually be undone: */
if defined RESULT set "RESULT=!RESULT:""="!^"
echo Now trimmed: `!RESULT!`
endlocal
exit /B
:TRIM
rem // This is the effective line that does the left- and right-trimming:
set "RESULT=%*" !
exit /B
I use this Python 2 script to print lines with trailing whitespace and remove them manually:
#!/usr/bin/env python2
import sys
if not sys.argv[1:]:
sys.exit('usage: whitespace.py <filename>')
for no, line in enumerate(open(sys.argv[1], 'rb').read().splitlines()):
if line.endswith(' '):
print no+1, line
I know that Python is not preinstalled for Windows, but at least it works cross-platform.

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= 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, i.e. 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
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
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.
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.
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
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);
}
}
}
Run it.
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)
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.
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%
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#
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.

How do you strip quotes out of an ECHO'ed string in a Windows batch file?

I have a Windows batch file I'm creating, but I have to ECHO a large complex string, so I'm having to put double quotes on either end. The problem is that the quotes are also being ECHOed to the file I'm writing it to. How do you ECHO a string like that and strip the quotes off?
UPDATE:
I've spent the last two days working on this and finally was able to kludge something together. Richard's answer worked to strip the quotes, but even when I put the ECHO in the subroutine and directly outputted the string, Windows still got hung up on the chars in the string. I'll accept Richard's answer since it answers the question asked.
I ended up using Greg's sed solution, but had to modify it because of sed/windows bugs/features (it didn't help that it came with no documentation). There are a few caveats to using sed in Windows: you have to use double quotes instead of single quotes, you can't escape the double quotes in the string directly, you have to endquote the string, escape using the ^ (so ^") then beqin quote for the next section. Also, someone pointed out that if you pipe input to sed, there's a bug with a pipe being in the string (I didn't get to verify this since in my final solution, I just found a way not to have all quotes in the middle of the string, and just removed all quotes, I never could get the endquote to be removed by itself.) Thanks for all the help.
The call command has this functionality built in. To quote the help for call:
Substitution of batch parameters (%n) has been enhanced. You can
now use the following optional syntax:
%~1 - expands %1 removing any surrounding quotes (")
Here is a primitive example:
#echo off
setlocal
set mystring="this is some quoted text"
echo mystring=%mystring%
call :dequote %mystring%
echo ret=%ret%
endlocal
goto :eof
:dequote
setlocal
rem The tilde in the next line is the really important bit.
set thestring=%~1
endlocal&set ret=%thestring%
goto :eof
Output:
C:\>dequote
mystring="this is some quoted text"
ret=this is some quoted text
I should credit the 'environment variable tunneling' technique (endlocal&set ret=%thestring%) to Tim Hill, 'Windows NT Shell Scripting'. This is the only book I have ever found that addresses batch files with any depth.
The following approach can be used to print a string without quotes:
echo|set /p="<h1>Hello</h1>"
pushing this string into file:
echo|set /p="<h1>Hello</h1>" > test.txt
pushing this string into file and appending a CR/LF:
echo|(set /p="<h1>Hello</h1>" & echo.) > test.txt`
To check:
type test.txt
You can use the %var:x=y% construction that replaces all x with y.
See this example what it can do:
set I="Text in quotes"
rem next line replaces " with blanks
set J=%I:"=%
echo original %I%
rem next line replaces the string 'in' with the string 'without'
echo stripped %J:in=without%
To remove all quotation marks from a set variable, you need Delayed Variable Expansion to securely expand the variable and process it. Expansion using percent signs (i.e. %VAR% and %1) are inherently unsafe (they are vulnerable to command injection; read this for details).
SETLOCAL EnableDelayedExpansion
SET VAR=A ^"quoted^" text.
REM This strips all quotes from VAR:
ECHO !VAR:^"=!
REM Really that's it.
To strip quotes from a text file or a command output, things will get complicated because with Delayed Expansion, string like !VAR! within the text document will get expanded (within the %%i expansion in FOR /F) when it shouldn't. (This is another vulnerability—information disclosure—that's not documented elsewhere.)
To safely parse the document, a switch between delayed-expansion-enabled and -disabled environment is needed.
REM Suppose we fetch the text from text.txt
SETLOCAL DisableDelayedExpansion
REM The FOR options here employs a trick to disable both "delims"
REM characters (i.e. field separators) and "eol" character (i.e. comment
REM character).
FOR /F delims^=^ eol^= %%L IN (text.txt) DO (
REM This expansion is safe because cmd.exe expands %%L after quotes
REM parsing as long as DelayedExpansion is Disabled. Even when %%L
REM can contain quotes, carets and exclamation marks.
SET "line=%%L"
CALL :strip_quotes
REM Print out the result. (We can't use !line! here without delayed
REM expansion, so do so in a subroutine.)
CALL :print_line
)
ENDLOCAL
GOTO :EOF
REM Reads !line! variable and strips quotes from it.
:strip_quotes
SETLOCAL EnableDelayedExpansion
SET line=!line:^"=!
REM Make the variable out of SETLOCAL
REM I'm expecting you know how this works:
REM (You may use ampersand instead:
REM `ENDLOCAL & SET "line=%line%"`
REM I just present another way that works.)
(
ENDLOCAL
SET "line=%line%"
)
GOTO :EOF
:print_line
SETLOCAL EnableDelayedExpansion
ECHO !line!
ENDLOCAL
GOTO :EOF
The delims^=^ eol^= in the code above probably needs explanation:
This effectively disables both "delims" characters (i.e. field separators) and "eol" character (i.e. comment character). Without it, the "delims" will default to tab and space and "eol" defaults to a semicolon.
The eol= token always read whichever the next character it is after the equal sign. To disable it this token has to be in the end of the options string so that no character may be used for "eol", effectively disabling it. If the options string is quoted, it might use quotation mark (") as the "eol", so we must not quote the options string.
The delims= option, when it's not the last option in the options string, will be terminated by a space. (To include space in "delims" it has to be the last option of FOR /F options.) So delims= followed by a space and then another option disables the "delims".
I know that it is not actually for the author, but if you need to send some text to the file without quotes - the solution below works for me. You do not need to use quotes in the echo command, just surround the complete command with brackets.
(
echo first very long line
echo second very long line with %lots% %of% %values%
) >"%filename%"
This worked for me:
SET "SOMETHING=Complex (String) (of stuff!)"
echo !SOMETHING! >> file.txt
This will turn "C:\Program Files\somefile.txt" into C:\Program Files\somefile.txt
while still preserving cases such as Height=5'6" and Symbols="!##
:DeQuote
SET _DeQuoteVar=%1
CALL SET _DeQuoteString=%%!_DeQuoteVar!%%
IF [!_DeQuoteString:~0^,1!]==[^"] (
IF [!_DeQuoteString:~-1!]==[^"] (
SET _DeQuoteString=!_DeQuoteString:~1,-1!
) ELSE (GOTO :EOF)
) ELSE (GOTO :EOF)
SET !_DeQuoteVar!=!_DeQuoteString!
SET _DeQuoteVar=
SET _DeQuoteString=
GOTO :EOF
Example
SetLocal EnableDelayedExpansion
set _MyVariable = "C:\Program Files\ss64\"
CALL :dequote _MyVariable
echo %_MyVariable%
The above answer (starting with :DeQuote) assumes delayed environment variable expansion is set to on. From cmd /?:
Delayed environment variable expansion is NOT enabled by default. You
can enable or disable delayed environment variable expansion for a
particular invocation of CMD.EXE with the /V:ON or /V:OFF switch. You
can enable or disable completion for all invocations of CMD.EXE on a
machine and/or user logon session by setting either or both of the
following REG_DWORD values in the registry using REGEDT32.EXE:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion
and/or
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion
to either 0x1 or 0x0. The user specific setting takes precedence over
the machine setting. The command line switches take precedence over the
registry settings.
If delayed environment variable expansion is enabled, then the exclamation
character can be used to substitute the value of an environment variable
at execution time.
The following batch file starts a series of programs with a delay after each one.
The problem is to pass a command line with parameters for each program. This requires quotes around the program argument, which are removed when the call is made. This illustrates a few techniques in batch file processing.
Look in the local subroutine :mystart for how an argument in quotes is passed in, and the quotes are removed.
#echo off
rem http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/if.mspx?mfr=true
rem Start programs with delay
rem Wait n seconds
rem n number retries to communicate with the IP address
rem 1000 milliseconds between the retries
rem 127.0.0.1 is the LocalHost
rem start /b (silent) /min (minimized) /belownormal (lower priority)
rem /normal provides a no-op switch to hold the place of argument 1
rem start /normal "Opinions" %SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion
rem ping 127.0.0.1 -n 8 -w 1000 > nul
rem Remove quotes in Batch
rem http://ss64.com/nt/syntax-dequote.html
rem String manipulation in Batch
rem http://www.dostips.com/DtTipsStringManipulation.php
rem ^ line continuation
rem
rem set p="One Two" p has the exact value "One Two" including the quotes
rem set p=%p:~1,-1% Removes the first and last characters
rem set p=%p:"=% Removes all double-quotes
rem set p=%p:cat=mouse% Replaces cat with mouse
rem ping 127.0.0.1 -n 12 -w 1000 > nul
rem 1 2 3 4
#echo on
call :mystart /b/min "Opinions" "%SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion" 8
#echo on
call :mystart /b/min "Notepad++" D:\Prog_D\Notepad++\notepad++.exe 14
#echo on
call :mystart /normal "Firefox" D:\Prog_D\Firefox\firefox.exe 20
#rem call :mystart /b/min "ProcessExplorer" D:\Prog_D\AntiVirus\SysInternals\procexp.exe 8
#echo on
call :mystart /b/min/belownormal "Outlook" D:\Prog_D\MSOffice\OFFICE11\outlook.exe 2
#echo off
goto:eof
:mystart
#echo off
rem %3 is "program-path arguments" with the quotes. We remove the quotes
rem %4 is seconds to wait after starting that program
set p=%3
set p=%p:"=%
start %1 %2 %p%
ping 127.0.0.1 -n %4 -w 1000 > nul
goto:eof
Using the FOR command to strip the surrounding quotation marks is the most efficient way I've found to do this. In the compact form (Example 2) it's a one-liner.
Example 1: The 5-line (commented) solution.
REM Set your string
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
REM Echo your string into the FOR loop
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO (
REM Use the "~" syntax modifier to strip the surrounding quotation marks
ECHO %%~A
)
Example 2: The 1-liner real-world example.
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO #ECHO %%~A
I find it interesting that the inner echo ignores the redirection characters '<' and '>'.
If you execute ECHO asdfsd>asdfasd you will write file out instead of std out.
Hope this helps :)
Edit:
I thought about it and realized there is an even easier (and less hacky) way of accomplishing the same thing. Use the enhanced variable substitution/expansion (see HELP SET) like this:
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
ECHO %STR:~1,-1%
That will print all but the first and last characters (your quotation marks). I would recommend using SETLOCAL ENABLEDELAYEDEXPANSION too. If you need to figure out where quotation marks are located in the string you can use FINDSTR to get the character #s.
Daniel Budzyński's response is brilliant. It works even in situations where there are special characters in the output. For example:
C:\> for /f "usebackq tokens=2 delims=:" %i in (`%comspec%\..\ping -n 1 -w 200 10.200.1.1 ^| \
findstr /c:"TTL="`) do echo|set /p="%i"
bytes=32 time<1ms TTL=255
If you try tried a simple echo without the quotes, you get a error, due to the "<" in the variable:
C:\> set "output=bytes=32 time<1ms TTL=255"
C:\> echo %output%
The system cannot find the file specified.
C:\> echo|set /p="%output%"
bytes=32 time<1ms TTL=255
Brute force method:
echo "foo <3 bar" | sed -e 's/\(^"\|"$\)//g'
This requires finding a suitable Win32 version of sed, of course.
http://unxutils.sourceforge.net/ is a native win32 port of a bunch of GNU utilities including sed, gawk, grep and wget. (sorry that I don't have enough rep to post this as a comment!)

Resources