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