How do you avoid cmd /c giving a broken error message when a file doesn't exist?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
taripo
Posts: 228
Joined: 01 Aug 2011 13:48

How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#1 Post by taripo » 21 Aug 2022 19:22

This, in CMD just running an executable, works

Code: Select all

C:\blah>"C:\Program Files\Windows NT\Accessories\zordpad.exe"
'"C:\Program Files\Windows NT\Accessories\zordpad.exe"' is not recognized as an internal or external command,
operable program or batch file.
Here, cmd /c gives a broken error message when a file doesn't exist ..

I understand that looking at cmd /?, that cmd /c and cmd /k , have some strange rules..

I thought maybe CMD /C with /S might be worth a try, maybe it'd make it behave sanely, i.e. preserving spaces, but it didn't. Maybe /S is less sane 'cos maybe /S is what they call "old behaviour".. Though both with and without /S seems strange to me and different to regular CMD parsing(i.e. without /C or /K).


C:\blah>CMD /C "C:\Program Files\Windows NT\Accessories\zordpad.exe"
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

C:\blah>CMD /S /C "C:\Program Files\Windows NT\Accessories\zordpad.exe"
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

C:\blah>
[/code]

I notice this works

Code: Select all

C:\blah>CMD /C "C:\Program^ Files\Windows^ NT\Accessories\zordpad.exe"
'C:\Program Files\Windows NT\Accessories\zordpad.exe' is not recognized as an internal or external command,
operable program or batch file.

C:\blah>CMD /S /C "C:\Program^ Files\Windows^ NT\Accessories\zordpad.exe"
'C:\Program Files\Windows NT\Accessories\zordpad.exe' is not recognized as an internal or external command,
operable program or batch file.

C:\blah>
Is that what you're meant to do?

Why are all the rules different when you use CMD /C or /K, and in this case regardless of whether /S is used or not..

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#2 Post by aGerman » 22 Aug 2022 00:16

It works like that (without code formatting to preserve color formatting):

CMD /C "command line"

The quotes around the command line are removed during the parsing process of the new cmd.exe instance. Parts of the command line that have to be quoted, need extra quotes here, too. E.g.

CMD /C ""command with spaces" arg_without_space"

Steffen

taripo
Posts: 228
Joined: 01 Aug 2011 13:48

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#3 Post by taripo » 22 Aug 2022 17:53

ok thanks.. so cmd /? shows

Code: Select all

   
        1.  If all of the following conditions are met, then quote characters
       on the command line are preserved:

       - no /S switch
       - exactly two quote characters
       - no special characters between the two quote characters,
         where special is one of: &<>()@^|
       - there are one or more whitespace characters between the
         two quote characters
       - the string between the two quote characters is the name
         of an executable file.

   2.  Otherwise, old behavior is to see if the first character is
       a quote character and if so, strip the leading character and
       remove the last quote character on the command line, preserving
       any text after the last quote character.
I see so /s or a non-existent executable, triggers the "old behaviour".

So hence we can put a wordpad.exe example into the same boat as zordpad.exe by adding a /s

Code: Select all

C:\>cmd /c "c:\Program Files\Windows NT\Accessories\wordpad.exe"

C:\>

C:\>cmd /s /c "c:\Program Files\Windows NT\Accessories\wordpad.exe"
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

The thing is, you say "The quotes around the command line are removed "

That could sound a bit like how bash -c is in that bash -c wants one argument.. and if there's a space then it has to be quoted/escaped, to be part of that one argument. And anything after that argument is ignored.

Though I see cmd /c echo a b c works.. so that makes it unlike bash -c..

So I don't see any need for quotes around the command line. 'cos cmd just counts everything after the /c as the command line anyway!!

But also, CMD isn't removing quotes around the command line, 'cos with CMD, the command line continues after the last quote! (mentioned in the extract from cmd /?) "preserving any text after the last quote character."

So e.g. case "2"(so-called old style), describes two possible cases.. One where it acts a bit like they are quotes around the command line(by seeing if the first character is a quote),.. and strips quotes(could call that 2b) The other where it acts like they are not quotes around the command line, and it acts like the quotes are there for escaping special characters., and it preserves them(could call that 2a). So whether it's doing case "1" or either of the two possibilities of case "2".. It's allowing text after whatever quote.

Code: Select all

C:\Users\User>cmd /s /c echo "a b c" d e f    <-- 2a
"a b c" d e f

C:\Users\User>cmd /s /c echo a b "c d" e f  <-- 2a
a b "c d" e f

C:\Users\User>cmd /s /c "echo a b c" d e f <--2b
a b c d e f

C:\Users\User>
So 2b that seems to try to be quotes around the command line is a flawed form of it because it allows stuff after the last or second quote.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#4 Post by aGerman » 23 Aug 2022 00:35

Admittedly I never got the point of option /s. Wondering if we already have a thread about that somewhere.
Nevertheless, I see how your 2a examples work, because there are no quotes surrounding the command line. 2b probably invokes some kind of undefined behavior since the command line does at least begin with a quote.
However, I actually just repeated how the OS builds the command line if you run a Batch file.

Code: Select all

@echo off
setlocal EnableDelayedExpansion
echo !cmdcmdline!
pause
If you run it via double click you may see something like that:

Code: Select all

C:\WINDOWS\system32\cmd.exe /c ""C:\Users\steffen\Documents\test.bat" "
Drücken Sie eine beliebige Taste . . .
If you drag drop a file onto it:

Code: Select all

C:\WINDOWS\system32\cmd.exe /c ""C:\Users\steffen\Documents\test.bat" C:\Users\steffen\Documents\test.txt"
Drücken Sie eine beliebige Taste . . .
So, you won't go wrong following this syntax, I guess.

Steffen

taripo
Posts: 228
Joined: 01 Aug 2011 13:48

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#5 Post by taripo » 23 Aug 2022 05:03

aGerman wrote:
23 Aug 2022 00:35
Admittedly I never got the point of option /s. Wondering if we already have a thread about that somewhere.
The point of /S is if you want the "old behaviour" (cmd /? mentions "old behavior"). So it forces old behaviour. or to put it another way, it forcibly skips the "new behaviour".

So for example suppose you do CMD /C __________ and either

i) What follows /C fits "new behaviour"
or
ii) What follows /C could vary, so might fit new behaviour or might fit old behaviour.
or
iii) Somebody is aware that for the same thing following _______ it might fit new behaviour or might fit old behaviour.. (e.g. if wordpad.exe isn't on the computer there, then it ridiculously flicks from new to old!)
or
iv) You want peace of mind that it'll follow the "old behaviour".

and e.g. maybe a person just prefers the "old behaviour" to the "new behaviour".

or

They don't like the ambiguity.

There wouldn't be a switch to force "new behaviour", because "new behavour" is very specific. The "New behaviour" is specifically for when you just have a basic situation, of you have an executable filename and the path to it has a space and you want the spaces escaped and are using quotes for that.

'cos in the old behaviour, a simple case of running an EXE when the path has a space, is a bit ugly.

As you can see in the old behaviour, (which I am forcing with /S),

This simple line won't work

Code: Select all

C:\>cmd /S /C "C:\Program Files\Windows NT\Accessories\wordpad.exe"
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

C:\>
(and indeed you've shown how to adjust it so it works for the "old behaviour")
aGerman wrote:Nevertheless, I see how your 2a examples work, because there are no quotes surrounding the command line. 2b probably invokes some kind of undefined behavior since the command line does at least begin with a quote.
it's defined behaviour..


Considering case "2"(so-called old style),which describes two possible cases. 2b(that's meant to be for quotes around the command line), and 2a(where it acts like they are not quotes around the command line and that they are for escaping special characters - besides space). And it tests for 2b by as per the documentation, by looking to see if the first character is a quote..

So 2b is the ("Look for the first quote") case.

The example I gave fitting 2b, is actually defined in cmd /?'s write up for case 2.

Code: Select all

..old behavior is to see if the first character is a quote character and if so, strip the leading character and remove the last quote character on the command line, preserving any text after the last quote character.
What it hasn't said, is that case "2" has two possible purposes. One of them, which is described there, is for when there are quotes around the command line. What it describes there is a broken form of quotes around the command line.

So my example just fits very much with what they wrote.. It's very defined.

They didn't define any case of "2" as being for quotes around the command line.

The quotes around the command line concept makes sense to me for linux but not for CMD. 'cos CMD doesn't use argv(i.e. it doesn't take arguments delimited by space), it just takes the whole command line anyway!

What is undefined , is what I described as the "2a"(No first quote) case.. I think what happens is won't follow the "new behaviour" or the "old behaviour", it will Normal behaviour.

So in a sense one could say that instead of saying there's "new behaviour", "old behaviour A", and "old behaviour B". . One could say there's a "3" which is follow normal behaviour. (as if one were at CMD and not doing /c).

So cmd /? could say that when doing /C or /K it will do 1 or 2 or 3. Where 1 is the new behaviour, 2 is the first quote case, and 3 is the normal behaviour. And dit does 1 otherwise 2 otherwise 3.
aGerman wrote: I actually just repeated how the OS builds the command line if you run a Batch file.

Code: Select all

@echo off
setlocal EnableDelayedExpansion
echo !cmdcmdline!
pause
If you run it via double click you may see something like that:

Code: Select all

C:\WINDOWS\system32\cmd.exe /c ""C:\Users\steffen\Documents\test.bat" "
Drücken Sie eine beliebige Taste . . .
If you drag drop a file onto it:

Code: Select all

C:\WINDOWS\system32\cmd.exe /c ""C:\Users\steffen\Documents\test.bat" C:\Users\steffen\Documents\test.txt"
Drücken Sie eine beliebige Taste . . .
So, you won't go wrong following this syntax, I guess.
That's really good, so by testing double clicking a bat, or drag and dropping a file onto the cmd window, you figured out the purpose of what they call "old behaviour". particularly the "first quote" case of "2".. Which is the only case mentioned in "2"..

You figured out that it's meant for when there are quotes around the command line.

Old behaviour is a bit ugly, so they came up with "new behaviour", which is for the very specific case of just there's two quotes spaces e.g..

CMD /C "path with spaces to wordpad.exe"

though the so-called "new behaviour" becomes ugly when that exe doesn't exist!

A person could just use the syntax that involves more than two quotes, and thus hits that way, onto the "old behaviour". and always using "old behaviour" the way it is really intended which is for quotes around the command line. (not having text after the command line)

It does open the question which I asked in another thread of what system uses old behaviour (and not "new behaviour")!!

Presumably there is one hence they call it "old behaviour"!!!

BTW i'm going to take a guess that they chose /S for "surround"..

Note- I could say /S forcibly skips "new behaviour", rather than that /S forces "old behaviour" because what kind of case would one call cmd /C abc"^"def

Code: Select all

C:\Users\User>cmd /c abc"^"def
'abc"^"def' is not recognized as an internal or external command,
operable program or batch file.

C:\Users\User>abc"^"def
'abc"^"def' is not recognized as an internal or external command,
operable program or batch file.

C:\Users\User>
I'd say It's normal behaviour.

So there aren't really two cases of old behaviour..

It's silly that cmd /? only mentions that /C doesn't mention that as a third option for when a case doesn't match the "surrounding quotes" method of old behaviour (by not starting with a quote)

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#6 Post by aGerman » 23 Aug 2022 11:30

Fun fact: In the German help text you will not even find someting like "old behavior". For that reason I really don't know what the English help message is talking about. Also, there is no hint that option /S means something like "new behavior". Not even in the English message. It will likely change the behavior somehow (otherwise it certainly wouldn't exist). However, I still have difficulties to understand what exactly /S is good for.

Steffen

(Quoting for reference:)

Code: Select all

Wird /C oder /K angegeben, wird der Rest der Befehlszeile nach der Option als
Befehlszeile verarbeitet, wobei folgende Logik zur Verarbeitung des doppelten
Anführungszeichens (") gilt:

    1.  Sind alle folgenden Bedingungen erfüllt, wird ein doppeltes
        Anführungszeichen auf der Befehlszeile beibehalten:

        - keine Option "/S"
        - genau zwei doppelte Anführungszeichen
        - keines der folgenden Zeichen zwischen den doppelten
          Anführungszeichen: &<>()@^|
        - es ist mindestens ein Leerzeichen zwischen den doppelten
          Anführungszeichen
        - die Zeichenfolge zwischen den doppelten Anführungszeichen ist der
          Name einer ausführbaren Datei

    2.  Ist dies nicht der Fall, wird bei einem doppelten Anführungszeichen
        als erstem Zeichen sowohl dieses, als auch das letzte doppelte
        Anführungszeichen entfernt (und der Rest der Befehlszeile bei-
        behalten).

taripo
Posts: 228
Joined: 01 Aug 2011 13:48

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#7 Post by taripo » 23 Aug 2022 11:50

aGerman wrote: Fun fact: In the German help text you will not even find someting like "old behavior". For that reason I really don't know what the English help message is talking about. Also, there is no hint that option /S means something like "new behavior". Not even in the English message. It will likely change the behavior somehow (otherwise it certainly wouldn't exist). However, I still have difficulties to understand what exactly /S is good for.

(Quoting for reference:)
Interesting

The German, translated to English "2. If this is not the case, a double quotation mark is used as the first character "

The English "2. Otherwise, old behavior is to see if the first character is a quote character and if so..."

The /S is for option "2" i.e. "old behaviour" not new behaviour. (not that the term old behaviour is even that useful without knowing why it's being called old!)

The idea is, there's a syntax mentioned in "2", that is versatile.. (and described in the English cmd /? as the old behaviour)..

The idea of /S is that if you have a command line that would or might meet the standards of "1" but you want it to use "2", then you use /S

The idea of "1", is purely so you can do something like CMD /C "C:\path with spaces in it\wordpad.exe". But if you aren't interested in that neat syntax, that is very specific to a very limited situation. Then, you can force it to use "2" by using /S

The /S is for the syntax called "old behaviour" or what you showed is the surrounding quotes syntax..

If something doesn't meet the requirements "1" then it'd look to see if it meets the "2" criteria/requirements. But suppose you have something that does meet "1" but you don't want it to get processed by that, you want it to get processed as "2" then you'd use /S

Technically /S will make it skip "1".. It's possible for it to not really meet "2" e.g. supposing the first character isn't a quote. Then you get normal behaviour.

I had a case where the "1" behaviour was annoying 'cos if an executable doesn't exist, e.g. suppose the executable doesn't exist, and it's in a path with spaces(as it is), then you a flawed error message.

Code: Select all

C:\>CMD /C "C:\Program Files\Windows NT\Accessories\wordpad.exe"  <-- works and hits "1"

C:\>CMD /C "C:\Program Files\Windows NT\Accessories\zordpad.exe"  <--  hits "2" and gives flawed error message 
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
Whereas if I want some consistency.. I'll use CMD /S /C and put in the surrounding quotes

Code: Select all

C:\>CMD /S /C ""C:\Program Files\Windows NT\Accessories\wordpad.exe""

C:\>CMD /S /C ""C:\Program Files\Windows NT\Accessories\zordpad.exe""
'"C:\Program Files\Windows NT\Accessories\zordpad.exe"' is not recognized as an internal or external command,
operable program or batch file.

C:\>
Then it uses "2" to parse it. And the error message makes sense.

So that's an example usage of /S.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: How do you avoid cmd /c giving a broken error message when a file doesn't exist?

#8 Post by aGerman » 23 Aug 2022 12:00

Technically /S will make it skip "1"..
Yeah, technically. But for my understanding it doesn't.

FWIW The only case where I've seen that /S is used is when a pipe creates another cmd process.

Steffen
Attachments
Screenshot 2022-08-23 195945.jpg
Screenshot 2022-08-23 195945.jpg (122.61 KiB) Viewed 5997 times

Post Reply