0

Suppose I generate such a script dynamically in a program of mine and hold it in a C++ string variable. How can I run it? Do I have to save it to a file first and then instruct cmd.exe to run it?

I know you can pipe commands into cmd.exe like this:

type script.bat | cmd

But the effect of that is not to run script.bat . Instead, windows starts a new cmd.exe instance, prints the logo and waits for commands which it echos to the screen before executing them. For instance, try

echo echo hello | cmd

Thus every line in script.bat is handled as an independent command, just as if you entered it on the command line (which is what cmd.exe thinks you are doing!). That's no good. You can't run general scripts like that. You may have loops and branches spanning several lines. So what can I do?

I know you can put several commands on one line like this:

cmd /C "echo hello & echo world"

But can every batch script somehow and easily be changed to a oneliner? If the script was:

@echo off

echo hello
echo world

I could replace it by the onliner above, but if it contains a for loop spanning several lines with brackets?

So the title question could be reformulated to: Can every batch script be transformed to a oneliner? If so then how? And if not, is there any good solution to the problem? Can I somehow trick cmd.exe into thinking that it reads a batch script from a file, while it actually gets it from a program of mine?

Edit: An interesting quirk is to do:

echo echo hello | cmd /C "for /f "tokens=*" %a in ('more') do @%a"

But again every line is interpreted as an independent command.

Henrik4
  • 464
  • 3
  • 13
  • Unless you can safely replace all new lines with ampersands, then no! – Compo Nov 29 '19 at 16:18
  • @Compo It's not correct to replace all newlines with &. A compound statement spanning several lines with brackets must not! – Henrik4 Nov 29 '19 at 16:39
  • Henrik4, a compound statement spanning several lines with brackets, does not need to span several lines. If that's your choice to do that, or you're unable to write that batch file as one complete command statement per line, then the answer is a straight no, and your examples are not representative of your actual task. – Compo Nov 29 '19 at 16:59
  • 1
    Perhaps [this answer](https://stackoverflow.com/questions/13320578/how-to-run-batch-script-without-using-bat-extension/13337597#13337597) may help you... – Aacini Nov 29 '19 at 17:01
  • @Aacini Yes, highly relevant and interesting. The article at dostips is very good. What you're proving is that translation of a general batch script to a series of independant commands is complicated! – Henrik4 Nov 29 '19 at 18:20
  • @Compo Yes, you must be right about that: if you can't translate a script into a series of independant commands then it's impossible. – Henrik4 Nov 29 '19 at 18:22

1 Answers1

3

FILE_ATTRIBUTE_TEMPORARY The file is being used for temporary storage. File systems attempt to keep all of the data in memory for quicker access rather than flushing the data back to mass storage. A temporary file should be deleted by the application as soon as it is no longer needed.

FILE_FLAG_DELETE_ON_CLOSE Indicates that the operating system is to delete the file immediately after all of its handles have been closed, not just the handle for which you specified FILE_FLAG_DELETE_ON_CLOSE. Subsequent open requests for the file will fail, unless FILE_SHARE_DELETE is used.

https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea

If you specify a temp file with these flags, you can run that as a batch. Unless you are under memory pressure the file will never be on the hard disk.

PS: Notepad will open web files if you type an URL into the Open File dialog. Notepad is a test bed for potential system features.

PPS: You can pipe it. cmd /c < ..\win.ini (not that this makes sense but we no longer have a standard batchfile in windows).

  • Great! This is very close to what I'm looking for. My only question now is: Am I allowed to create a temporary file even if I don't have write access to the hard disk? – Henrik4 Nov 29 '19 at 19:09
  • Probably not. But what scenario has a program with nowhere to write. **PS** Half of simple batch files will execute as commands if you enclose the batch in brackets and change `%%` to `%`. First line = `(` and last line = `)`. –  Nov 29 '19 at 19:14
  • Maybe I can write but I'd like to avoid hard disk writes. I want everything to happen in memory. – Henrik4 Nov 29 '19 at 19:20
  • What do you mean, execute as commands? I can't put a multiline script on the command line. – Henrik4 Nov 29 '19 at 19:22
  • You can pipe it. `cmd /c < ..\win.ini`. –  Nov 29 '19 at 19:40
  • If you use those flags it will be in memory only. But you have to treat it as a file. –  Nov 29 '19 at 19:41
  • You can pipe from memory by taking over stdin and sending you multiline list of commands (I can't call it a batch file). –  Nov 29 '19 at 19:42
  • No, cmd /c < ..\win.ini doesn't work. If you use the /C flag it takes the command from the command line and reads nothing from stdin, so it's useless to redirect. – Henrik4 Nov 29 '19 at 19:58
  • Yes, I know I can pipe into cmd.exe but then it won't be a batch program anymore but a sequence of commands. Not the same thing! – Henrik4 Nov 29 '19 at 20:01
  • Just try putting a bracket on first and last lines. –  Nov 29 '19 at 20:20
  • The effect of putting a bracket on the first and last lines is that cmd.exe will output "more?" after each command inside and wait for all the commands to finish before outputing anything. Pointless. I should do this: type script.bat | cmd.exe > nul and redirect all output in the script to con. But I also have to change %%a to %a in for loops and avoid using %1, %2 etc. – Henrik4 Nov 29 '19 at 20:37
  • Don't do it then. It not proper programming which is why its not easy. `console.writeline("text")` does exactly the same. –  Nov 29 '19 at 20:54