The redirection can come anywhere on the line, and you can use that to get rid of the spaces


We saw last time that the redirection can come anywhere on the line, and we saw that unquoted paths with embedded spaces can seem to work, but in fact doesn't. And you don't notice because the command processor is not parsing the command the way you think.

Another problem with redirection is the unwanted trailing spaces. If you say

echo foo >result.txt

then the file result.txt consists of six characters:

f o o   \r \n

Notice that there's a space before the CR+LF. You probably didn't want that space, but it's there because you put a space before the redirection operator. The parser takes out the redirection operator and the file name, but the space before the redirection operator is still there.

You can remove the space by squishing the redirection operator right against the string you want to print.

echo foo>result.txt

Now the resulting file is

f o o \r \n

Cool. No stray space.

And then later you get a bug because this string didn't get saved to the file properly:

set MESSAGE=2 for 1
echo %MESSAGE%>result.txt

The resulting file is

2   f o r   \r \n

Where did the 1 go?

Another part of the syntax for redirection is that if you put a number in front of the redirection operator, it specifies which file descriptor you want to redirect. In practice, this number is nearly always 2 (stderr), because 1 (stdout) is the default, and 0 is stdin, which nobody writes to. But it means that the expansion of the command line becomes

echo 2 for 1>result.txt

and you are now performing an explicit redirection of stdout. The 1 is redundant because the default is stdout, but hey, you asked for it.

To get rid of this space, you can take advantage of the principle in the subject of today's post. Put the redirection operator somewhere else. I like to put it at the front.

>result.txt echo %MESSAGE%

Putting the redirection at the front also makes building a multi-line document easier to read.

rem old way
echo first line>result.txt
echo second line>>result.txt
echo third line>>result.txt

rem new way
 >result.txt echo first line
>>result.txt echo second line
>>result.txt echo third line
Comments (28)
  1. The MAZZTer says:

    It’s worth mentioning I tried this to see if it would work:

    echo %MESSAGE%1>result.txt

    No dice. cmd.exe takes the full number before the > even if it’s multiple digits. Since it doesn’t know what 11 is supposed to be it ignores it outright, and you’ve just bought 2 for 11, which is quite a bad deal.

    Because of legacy compatibility oddities like this, I personally would advise against using batch for anything except simple scripts*, and powershell or a full compiled program for anything complex. The only reason you might want to use batch for something more complex and really be justified would be if the target machine is old enough to lack powershell (and MS does not support any versions of Windows in this configuration anymore so this is increasingly unlikely) and you are working on someone else’s (eg a workplace) PC with no access to any sort of real development tools (or, maybe you don’t know powershell or any full development languages. In which case I encourage you to learn powershell. You managed batch, so I know you can do it).

    * – Such as, for example, launching powershell with permissive ExecutionPolicy to run your powershell script I suggested you write.

    Free batch redirection tip if you’ve chosen to ignore all the above:

    2&>1 will redirect stderr to stdout, so they both end up in the same stream. Likewise you can simply do 2>file.ext to capture stderr to a file. You could potentially use the for command to figure out if any text was logged there, and thus determine if an error occurred. But that’s only necessary if the command does not set %ERRORLEVEL% on error.

    (Of course, it’s a lot easier if you use a language that has error handling built in.)

    1. florian says:

      Wouldn’t the redirection be 2>&1 (instead of 2&>1)?

      About redirection: this link explains how to pipe multiple lines to another program, and this is my most frequently used method to invoke SQL commands:

      http://web.archive.org/web/20160101134129/http://www.misanthropicgeek.net/?p=469

      What was that PowerShell thing everybody is talking about?

    2. morlamweb says:

      @Mazzter: I continue to use batch files for “complex” scripts that have already been written as batch files, are well-tested, and converting them to The New Thing(TM) would require far more time than I’d gain from running the “improved” versions. New scripts, perhaps should be written for The New Thing(TM), but inertia tends towards batch files.

      “(Of course, it’s a lot easier if you use a language that has error handling built in.)”
      “Batch” is not a language. It’s a set of commands, in a command processor, with a few rudimentary flow-control options. Let’s try to keep that in mind.

  2. nathan_works says:

    I feel bad asking, because I know I’ve written bash-script code like “if [ $var1 -eq 1 ];” type stuff to see if $var is empty (so it is evaluated like “1 -eq 1”).. but .. Would quotes/quoting fix the spaces and numbers problem ?

    1. Peter Doubleday says:

      Tokens, dear boy. Tokens.

      Naturally, one has to be able to process the tokens within some sort of semantic domain. Which is where a proper scripting language comes in. (See Mazzter, above.)

    2. alegr1 says:

      This obvious solution works:
      if [ “$var1” == “” ]

    3. Antonio Rodríguez says:

      Of course, it also works in batch files. I use the following to show help when no parameter is given:

      if “%1″==”” goto help

    4. Some really old shells (we’re talking /bin/sh, not /bin/bash) don’t support certain fancy modern features like testing for equality with the empty string or testing for non-emptiness. It’s for compatibility with these ancient shells that the configure scripts that GNU Autotools spits out have all these crazy tests like:

      if test “x${FOO}” == “x”; then …

      But if you’re writing shell code for any shell released in the last decade or two, that’s completely unnecessary. Just go with:

      if [ -z “$FOO” ]; then …

      or

      if [ “$FOO” == “” ]; then …

      1. heto says:

        test -z and testing against the empty string are mandated by POSIX, so they should work on any /bin/sh even if it’s not bash. Then again, a relatively popular UNIX implementation ships with a /bin/sh with poor POSIX compatibility; for some reason, a more compatible sh is available under another path (leaving the path out so as not to identify which product and thus vendor this is). However, even that /bin/sh supports empty strings with [; what I noticed it lacks support for is $(command).

        However, using the == operator with test is a bash extension. With POSIX and most (all?) other shells than bash, only one equals sign is accepted.

  3. Peter Doubleday says:

    I hate to bang on about this. (No, I lie.) But the first rule of parsing is -don’t talk about parsing- ignore the “fluff” between tokens. And when I say, “fluff,” I mean “white space.”
    But, of course, this example turns that around by 180 degrees. Because the set string is implemented as a macro substitution, rather than as a token in its own right, you get this nonsensical case where the lucky [0..2] digit slurves into a random following token to produce an unexpected redirection.
    This sort of thing is very difficult to reason about. I’ve given up on DOS batch scriptinging and *nix shell scripting (which is actually far, far, worse) in favor of something that actually does the job properly — a decent scripting language. Python, Perl, even PowerShell. I’d prefer something cross-platform, but then again, the main criterion is that it was not built in the Stone Age.

    Having said which, I appreciate the fact that my view is in the minority when hiring new IT guys: a good 80% or more of effort is devoted to supporting this nonsense. And given that, I for one, support Batch File Week!

    1. Peter Doubleday says:

      I’m a little paranoid about being accused of going off-topic, so … Here’s the thing about Raymond’s post here.

      I can pretty much guarantee that anything you have learned, either at college or at work, would suggest that you don’t really need to watch out for trailing spaces.

      And you are wrong. Weird, but interesting.

    2. Antonio Rodríguez says:

      Batch files are a lot simpler once you stop thinking in terms of regular parsed-and-compiled languages, and forget about tokens, grammars and preprocessors.

      Empty your mind. And take these simple facts:

      1) Command interpreters interpret lines. Batch files/shell scripts are just a collection of lines, executed in order.
      2) A line is a string of space-separated, optionally quoted, parameters, which end in a line delimiter.
      3) Before executing a line, the command interpreter will substitute all its variables for their values, and then it will take note of and remove redirections. Without inserting or removing extra spaces.
      4) The first parameter in a line is the command. The remainder are passed as a single string to the command (including trailing spaces), which is in charge of parsing it and extracting the parameters. Thus, for the command interpreter, the only “special” parameter is the first one (%0 in cmd.exe’s notation).

      That’s all. There are some wrinkles, mainly in the flow control commands (if, for, case, while…), but with those four rules and a bit of logic you can work almost everything. If you follow these rules, you will see that there isn’t anything special about the set command, either – all the magic happens in rule 3, during expansion.

    3. Muzer says:

      *nix shell scripting far worse? In that people’s expectations are higher than for batch, maybe, but could you tell me how it’s actually worse? The problem listed here (trailing spaces) most definitely doesn’t occur in Bourne-like shells.

    4. Antonio Rodríguez says:

      Unix shell scripts are years ahead of batch files. When Microsoft/IBM came with DOS 1.0 in 1981, the Bourne Shell already was a mature tool. In the NT/2000/XP years, Microsoft worked hard to close the distance (and did a good work, because Unix shells didn’t have much improvements left). But sadly all this ended with the launch of PowerShell. Now, there is no hope that CMD.exe will ever reach parity with bash.

  4. Antonio Rodríguez says:

    > You managed batch, so I know you can do it.

    Yes, I can do it. Of course I can. I have lost count on how many languages I know (probably over a dozen, including two or three developed by myself), so learning a new one should be no problem.

    Except that it would take time to master. Even more if you account for the effort that would take to translate into PowerShell the batches I have written over the years (more than a hundred, some of which include calls to GNUWin32 commands). In my case, learning, for example, the sub-commands of sed or grep makes more sense than learning to do the same with PowerShell, because I can use them in Unix too, when doing web administration.

    Batch files may not be as elegant as PowerShell scripts (you may say they are ugly, and I won’t disagree). But they do work, and they take no time away from my (paid) work. I guess many people will be in my shoes.

    That’s why I love Batch File Week (will it be a week-and-a-half this year? Please? With a cherry on top? O:-) ).

    1. ErikF says:

      Also, cmd/command is *still* the least common denominator if you have to maintain Windows installations that don’t have PowerShell on them, or where you are stuck with PS that is in restricted execution mode. Unix is in a similiar spot, where the Bourne Shell still reigns supreme even though some people wish it would die a quick death.

      1. voo says:

        If you’re still supporting systems that don’t come with PowerShell pre-installed, you have much, much bigger problem than the choice of your scripting language. Not even Microsoft is supporting an OS that doesn’t any more, so it may just be time to move on yourself.

        And no there’s no problem at all with restricted mode. A simple “PowerShell.exe -ExecutionPolicy Bypass -File ” will do the trick.

        That’s also a handy way to provide PowerShell scripts that can easily be executed from Explorer independent of how the system is set up –
        put the above into a batch script (such a wrapper is probably the only sane reason for writing a new batch file these days).

      2. James says:

        You instead could use WSH (i.e., cscript) with VBscript or JScript. I think that’s been installed with Windows since Windows 98.

        1. xcomcmdr says:

          I prefer batch or PowerShell over VBScript/JScript….

          Besides I block WSH on every installation since the Windows XP days. :p

  5. Putting it at the start works?!? Having used batch files for like 30 years i can’t believe i haven’t seen it before

  6. Neil says:

    In case anyone reading yesterday’s comments wonders what happened to my timeout/t 1>nul, it became timeout/t>nul 1.

  7. BZ says:

    Regarding environment variable expansion with redirection operator, I have a feeling that this is the type of thing that can be changed now without worrying about backward compatibility because nobody would ever have written code that did this except by mistake. I can’t imagine someone using a variable to decide what they want to redirect to a file, or interacting with the redirection operator in some other way.

    1. set OUTPUT=2
      if save-normal-output set OUTPUT=1
      some-command %OUTPUT%>output

      1. BZ says:

        That is a contrived example because it can only redirect one thing at a time. How often do you want to redirect EITHER stdout OR stderr? I’d imagine either none, one, or both.

        1. Martin Bonner says:

          How often? Not often, but there are a LOT of Windows installations out there. Somebody, somewhere, *would* be broken by this change.

  8. Nathan says:

    >result.txt (
    echo first line
    echo second line
    echo third line
    )

  9. I would like to take the opportunity to mention the “Batchography” explaining all there is to be explained about Batch files programming. It is written in 2016 and one of the most complete reference book with more than 100 Batch recipes and troubleshooting tips.

Comments are closed.

Skip to main content