1

I'm making a little text-based BATCH game and am trying to store a value (ex. 04) in a .txt file, close the command prompt window, then reopen it and have it set the color to the value in that file. If the file does not exist, I want it to create the file and place a placeholder value (ex. 07) in it. It worked previously with the file in the same directory, but in the name of neatness I need this file in the subfolder.

The code to store the value in the file works fine:

:textred
cls
set /a %color%=04
color 04
cls
echo Text color set to red!
echo 04 > %~dp0\SettingsVariables\color.txt
pause
goto settings

The value is stored, overwriting the previous value. The problem is in the code to open and read or create and write:

if exist %~dp0\SettingsVariables\color.txt (
    set /p color=<%~dp0\SettingsVariables\color.txt
    color %color%
)
if NOT exist %~dp0\SettingsVariables\color.txt (
    @echo 07>%~dp0\SettingsVariables\color.txt
    color 07
)

The code that creates the file and places the default value in it works just fine but after it is created and then modified by the previous block of code, it fails to read the text in the file and set the color as that value. What am I doing wrong? I'm not too experienced in BATCH so I'd greatly appreciate an explanation of what your answer does. Thank you!

4person
  • 11
  • 2
  • Please open a [command prompt](https://www.howtogeek.com/235101/), run `set /?` and read the output help. You will find out that `set /a %color%=04` is of wrong syntax as it instructs `cmd.exe` to evaluate an arithmetic expression to convert the ASCII string of the octal number `04` (in bytes 0x30 0x34 0x00) to a 32-bit signed integer (in bytes 0x04 0x00 0x00 0x00), then convert the resulting integer `4` back to a string (in bytes 0x34 0x00) and assign that string to the environment variable of which name is assigned to the environment variable `color`. – Mofi Dec 31 '22 at 11:09
  • There is no environment variable `color` defined at all by your batch file. The result is the execution of `set /a =04` as it can be seen on [debugging the batch file](https://stackoverflow.com/a/42448601/3074564) resulting in the error output `Missing operand.` because of environment variable name left to equal sign is missing. See also [Why is no string output with 'echo %var%' after using 'set var = text' on command line?](https://stackoverflow.com/a/26388460/3074564) It is in general good not using labels and environment variable names identical to Windows commands. – Mofi Dec 31 '22 at 11:12
  • However, `set /a %color%=04` is completely useless and should be removed for that reason. The storage of the string with foreground and background into a text file could be done with either `(echo 04)>"%~dpn0.ini"` or `>"%~dpn0.ini" echo 04`. See [Why does ECHO command print some extra trailing space into the file?](https://stackoverflow.com/a/46972524/3074564) for the reason of using the special syntax in this case. It is better to store the setting of the batch file in same directory as the batch file with same name as the batch file and just the different file extension `.ini`. – Mofi Dec 31 '22 at 11:17
  • By the way: `%~dp0` expands always to a directory path ending with a backslash. It is wrong by design to concatenate `%~dp0` with a file/folder name or a wildcard pattern with adding an additional backslash. The Windows file I/O functions need to correct that syntax error by removing the additional, second ``\`` before passing the resulting string to the file system as explained by Microsoft in the documentation about [Naming Files, Paths, and Namespaces](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file). – Mofi Dec 31 '22 at 11:20
  • Put quotes around the whole file path… – aschipfl Dec 31 '22 at 11:21
  • The are two lines required to read back the setting. The first command line is: `if exist "%~dpn0.ini" for /F "usebackq" %%I in ("%~dpn0.ini") do set "ColorValues=%%I"` It is possible that the INI file does not exist or does not contain any line. There is required therefore a second command line to make sure the environment variable `ColorValues` is finally always defined. The second command line is `if not defined ColorValues set "ColorValues=04"`. – Mofi Dec 31 '22 at 11:26
  • Well, it would be good to have above these two command lines `set "ColorValues="` to explicitly undefine a perhaps already defined environment variable `ColorValues` or `set "ColorValues=04"` to explicitly (re)define this environment variable with the default string value before loading it from the INI file if that file exists at all and is not empty. See [How to save/load variables of a batch file game to/from a text file?](https://stackoverflow.com/a/68967273/3074564) and the __issue__ chapters in [this answer](https://stackoverflow.com/a/60686543/3074564) why using `"` around `%~dpn0.ini`. – Mofi Dec 31 '22 at 11:31

1 Answers1

0

To solve your problem, you need to be aware of a number of issues.

It's regarded as unwise in any programming language to use a keyword as a variable-name.

ALL variables in batch are STRINGS. No exceptions.

set /a allows pure-numeric strings to be used as if they were numeric values and perform calculations using those values. It also allows variable names alone to be used in calculations - without requiring the % delimiters.

The result of a set /a calculation is stored in suppressed-leading-0 decimal format.

In a set /a, a leading 0 has special significance. If the value begins 0x then the value is interpreted as HEX, otherwise of the value begins 0, then the value is interpreted as OCTAL.

If a redirector (><|) is directly preceded in the source by any numeric character, then the redirection takes place of the nominated "stream" - 0=keyboard, 1=standard output, 2=standard error; others unused)

"quoting a string" causes cmd to interpret the string as a single entity, even if it contains spaces or other separators. This is especially useful for absolute filenames (containing paths).

Tip: Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.


The color syntax is color bf where b is the background colour and f the foreground. These characters are hex (0..9,a..f;case-insensitive) therefore the instruction color %myhues% must have myhues set to a 2-character string, each character being hex.

So, set /a will yield a leading-zero-suppressed decimal result, it's inapplicable for controlling color settings.

Your code

echo 04 > filename

will actually record 04SpaceCRLF on the file (you'll see the filelength is 5) because the space appears before the redirector.

So - you remove the space

echo 04> filename

... and it doesn't work, because 4> redirects stream4 to the file.

You could use

echo 0^4> filename

Where the caret (^) "escapes" the special meaning of the 4. But that's really awkward.

The normal method would be

> filename echo 04

which is fine, provided filename contains no separators and there are no trailing spaces on the line.

So

> "filename" echo 04

is better; the space after the > is optional (and extra typing)

So, you need to assign a string of two hex characters to myhues as appropriate.

What might be useful is this:

:setbgred
set "myhues=4%myhues:~-1%"

to set the background colour to red(4) and keep the current foreground.

There are oodles of examples of how to use substringing in batch on SO. As a last resort, you could even read the documentation (from the prompt: set /?)

Magoo
  • 77,302
  • 8
  • 62
  • 84