How would I set each line of a text document to separate variables using batch? - file

How would I set a each line of a text document to separate variables using Batch? I know how to set a variable to the first line of a text document using:
Set /p Variable=<Test.txt
...but I don't know how to read other lines of the file. Lets say for example I had a text document with 3 lines, the first line had 'Apples' written on it, the second had 'Bananas' and the third had 'Pears', and lets say the document was called Fruit.txt. How would I set the variable 'Line_1' to the first line of the document, 'Line_2' to the second line and 'Line_3' to the last line?. Just to keep it simple, lets just say the batch file and Fruit.txt are both in the same folder. I don't want to do this in VBScript, so please only post Batch code. I would have thought that it would be something like:
#Echo off
Set /p Line_1=<Fruit.txt:1
Set /p Line_2=<Fruit.txt:2
Set /p Line_3=<Fruit.txt:3
Echo Fruit 1 is %Line_1%, Fruit 2 is %Line_2% and Fruit 3 is %Line_3%
Pause
Exit
...but quite clearly it isn't. Any help?

EDIT: This is for arbitrary-length files, then. jeb has an answer that solves your particular problem for a known number of lines. I will leave this here, though, as I hate deleting posts I put some time into for explanation :-)
Well, you obviously need some sort of counter. Let's start with 1:
set Counter=1
Then, you need to go line-wise through the file:
for /f %%x in (somefile) do ...
Then store the line in a numbered variable (that's what we have the counter for):
set "Line_!Counter!=%%x"
aaaaand increment the counter:
set /a Counter+=1
And that's it. Add a few more necessary things, you know, the boring stuff that's always needed in such cases (strange statements before and after, block delimiters, etc.), and you're done:
#echo off
setlocal enabledelayedexpansion
set Counter=1
for /f %%x in (somefile) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
)
set /a NumLines=Counter - 1
Echo Fruit 1 is %Line_1%, Fruit 2 is %Line_2% and Fruit 3 is %Line_3%
rem or, for arbitrary file lengths:
for /l %%x in (1,1,%NumLines%) do echo Fruit %%x is !Line_%%x!
Some explanation:
set /p Var=<file will set the variable to the first line of a file, as you noted. That works because set /p will prompt for input and < file will redirect the file into standard input of a command. Thus set /p will interpret the file's contents as the entered input up until the user hits Return (i.e. the file contains a line break). That's why you get the first line. The system would throw the whole file at set /p but since the command only reads the first line and then is done they just get discarded.
The syntax you were proposing there is actually for accessing Alternate Data Streams of files on NTFS, which is somethhing totally different.
<short-detour> However, jeb has a way of reading multiple lines. This works because the block (delimited by parentheses) is a single command (see below) you can redirect a file's contents into. Except that command is comprised of multiple statements, each of which will read a single line and store it away. </short-detour>
Which brings us to for /f which iterates over the contents of a file (or the output of a command) line by line and executes a command or block of commands for each line. We can now read the whole file into as many variables as there are lines. We don't even need to know how many in advance.
You may have noticed the Line_!Counter! in there which uses Counter a little bit differently from how you're used to use environment variables, I guess. This is called delayed expansion and is necessary in some cases due to how cmd parses and executes batch files. Environment variables in a command are expanded to their values upon parsing that command. In this case the whole for /f including the block containing two statements is a single command for cmd. So if we used %Counter% it would be replaced by the value Counter had before the loop (1) and never change while the loop is running (as it is parsed once and run multiple times. Delayed expansion (signaled by using ! instead of % for variable access changes that and expands environment variables just prior to running a command.
This is almost always necessary if you change a variable within a loop and use it within the same loop again. Also this makes it necessary to first enable delayed expansion which is done with the setlocal command and an appropriate argument:
setlocal enabledelayedexpansion
set /a will perform arithmetic. We use it here to increment Counter by one for each line read.

To read multiple lines with set/p you need brackets around the set/p block.
#Echo off
(
Set /p Line_1=
Set /p Line_2=
Set /p Line_3=
) <Fruit.txt
Echo Fruit 1 is %Line_1%, Fruit 2 is %Line_2% and Fruit 3 is %Line_3%

Related

Batch File - How to copy text from file, and then update it to a new value

Each time I open the batch file, I would like it to read the information currently stored in the text file, and then apply that stored information it pulled to calculating a new integer.
I'm trying to figure out how to get a number copied from a text file, stored as a variable, and then updated to a new integer in that text file, say adding 1 to the value.
I've been sifting through information online, and everything seems to point in a different direction.
Here is a test code I've gotten from digging thus-far:
set file="Test.txt"
set /a _Counter =< %file%
echo:%_Counter%
set /a "_Update=%_Counter%+1"
echo:%_Update% >%file%
timeout /t 10
For some reason when I try to get the information for the counter, it doesn't pull any data from the text file, and I'm left with this line output by the batch file.
F:\Users\Test\Documents\JumbledDirectory> set /a _Counter = Directory\Test.txt 0<F:\Users\Test\Documents\Jumbled
The most common answer I've seen is to use something along the lines of
set /p _Counter=< Test.txt
echo %_Counter%
As seen here: Windows batch command(s) to read first line from text file
But upon doing this I've either ended up with
echo:%_Counter%
being completely blank, or it defaults to 0 each time.
Any help would be appreciated as I've sadly been trying to find how to get this simple function for around 6 hours now.
#ECHO Off
SETLOCAL
set "file=q72474185.txt"
set /p _Counter=< "%file%"
echo:%_Counter%
set /a _Update=_Counter+1
echo:%_Update% >"%file%"
TYPE "%file%"
GOTO :EOF
When you use the point-click-and-giggle method of executing a batch, the batch window will close if a syntax-error is found or the script runs to completion. You can put a pause after statements and home in on the error, but better to open a 'command prompt' and run your batch from there so that the window remains open and any (error) messages will be displayed.
The error message would be about missing operand.
I've changed the filename as I track each question I respond to with its own set of data.
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign a terminal \, Space or " - build pathnames from the elements - counterintuitively, it is likely to make the process easier.
set /a does not expect input from anywhere, it simply performs the calculation and assigns the result. Quotes are not necessary so I've removed them. % are also not required in a set /a but can be required if you are using delayedexpansion.
set /p expects input, so I've used that to read the file. Note that set /a disregards spaces, but set and set /p will include the space before the = in the variablename assigned, and _Counter & _Counter are different variables.
So having the batch in the same directory as the textfile this will work:
REM get input of file as Counter
set /p Counter=<number.txt
REM add a number to Counter and assign it as Counter
set /a "Counter=%Counter%+3
REM empty the file
break>number.txt
REM write Counter in the file
echo %Counter% >> number.txt

Saving variables in a text file

I'm trying to load and save variables into a file.
For example:
#echo off
set /a number=1
echo %number%>text.txt
How do I store the number from the text file in a variable for example variable1?
As mentioned by aschipfl, there are two ways to do it:
Using set /P (redirect variable to a text file and read (the file) with set /p).
Parse the file using a for /F loop.
As the first way is already mentioned by Tiw, I will only deal with the second one. You should do:
#echo off
set "number=1"
(echo %number%)>text.txt
for /F "delims= eol=" %%A IN (text.txt) do set "variable1=%%A"
Note that:
/a option in set is used only to perform arithmetic operations. It doesn't mean that the interpreter will 'see' this as a number.
The parentheses are added for security. They prevent echoing an extra space in the txt file. echo %number%>txt won't work if %number% is <10 because 0 is STDIN, 1 is STDOUT, 2 is STDERR and numbers from 3 to 9 are undefined. Apparently, it's sending STDIN/STDOUT/STDERR/UNDEFINED of nothing to a file.
Further reading:
https://ss64.com/nt/syntax-redirection.html
https://ss64.com/nt/for_f.html
https://ss64.com/nt/set.html
Your code will lead to problem, better change to:
#echo off
set /a number=1
>text.txt echo %number%
Another way of the last line is:
echo %number% 1>text.txt
1 means STDOUT, that's why your code won't write 1 to the file text.txt.
And to read the file into variable1:
set /p variable1=<text.txt
Note when there're multiple lines in the file, only first line will be read into the variable1.
From comment, and changed a little bit:
if not exist "%~dp0settings.gsf" (
echo.>"%~dp0settings.gsf"
goto :createsave
) else (
echo Reading your savefile...
set /p lang=<settings.gsf
)
%~dp0 will end with \, so no need to add another \.
You should close the else block, and it's better to indent and put ) else ( in a single line.
Try change according this, see if it works.
-- Indentation is good for readability and debugging, in other programming languages too.

Using xcopy or copy for a single file from multiple folders

So in the batch script I'm building I am taking a single file from a folder, copying it over to a destination folder, and renaming it based on the number of times that the script has been looped. Essentially I need to take a file that's named the samething from a bunch of different folders spread across multiple computers at times and copy them into a new folder to work with. I've read up on xcopy and copy as that seemed like the thing to use but I haven't been able to find anything that lets me tell it to only copy over a single named file. I've posted what I have so far for the script below with commented lines for the sections I haven't figured out:
ECHO off
SETLOCAL enabledelayedexpansion
ECHO Note: Your combined permission list cvs can be found in the desktop folder
SET /A #=-1
:start
SET /A #+=1
:again
ECHO Please input the file path to the permissionoutput.txt
SET /p permissionoutputpath=
SET "sourcefolder=%permissionoutputpath%"
SET "destinationfolder=C:\Users\kayla\Desktop\HOLDER-CombinedPermissionsLists"
IF not exist "%sourcefolder%\permissionoutput.txt" Echo file not found&goto again
copy "%sourcefolder%\permissionoutput.txt" "%destinationfolder%\permissionoutput%#%.txt"
ECHO Add another file to combine: y or n?
SET /p addanotherfile=
if %addanotherfile%==y goto :start
UPDATE: Code corrected with answer to be fully functional for use as a reference
SET /A #=-1
:start
SET /A #+=1
:again
ECHO Please input the file path to the permissionoutput.txt
SET /p permissionoutputpath=
SET "sourcefolder=%permissionoutputpath%"
SET "destinationfolder=C:\Users\kayla\Desktop\HOLDER-CombinedPermissionsLists"
IF not exist "%sourcefolder%\permissionoutput.txt" Echo file not found&goto again
copy "%sourcefolder%\permissionoutput.txt" "%destinationfolder%\permissionoutput%#%.txt"
ECHO Add another file to combine: y or n?
SET /p addanotherfile=
if /i "%addanotherfile%"=="y" goto start
# is a legitimate variable-name. It's initialised to -1 then incremented on each loop through :start so the first value it will have when it's used is 0. (If you want to start at 1 just initialise it to 0 instead)
Next - your sets - BUT spaces are significant in a string set command are would be included in the variablename/value assigned if present in the set instruction. "quoting the assignment" ensures any stray trailing spaces on the line are not included in the value assigned.
Well - next, make sure the file exists and if it doesn't, then produce a message and loop back to :again which bypasses the increment of #.
Otherwise, simply copy the file. You're aware of its sourcename, and your destinationname is constructed by including %#% to include the current value of # (all batch variables without exception are strings - the set /a instruction merely converts from string to binary to perform the required calculation, then converts the result back to a string for storage in the environment.)
Finally, interpreting the request to add another file. if /i makes the comparison case-insensitive. Since you have no direct control over the user's response, "quoting each side" ensures the if syntax isn't violated in case the user enters "yup sure 'nuff" or some other unexpected response.
The leading colon is not required in a goto. I prefer to omit it to keep conguity with the call command where no-colon means an external routine will be called and a colon means the routine is in this batch file.

How do I extract a single digit from a string in a .txt file on CMD?

I tried Googling this but I didn't quite find a clear solution so I'm asking you.
I'm not sure how to put this but, let's say we have a TEXTFile.txt that contains a line of a string with random letters and numbers (like AJS12U3254FU8AD). Now, what I want to do is ask the user to enter a number with set /p number=, and then echo the digit/character from the string that this number represents. For instance (on the previous string example) if the user inputs number 3, I want the batch script to echo the letter S, if he inputs 4 to echo 1 and so on.
In my little experience, i think this problem comes down to echoing certain digits from a variable, like echo %var:~0,1% but instead of using integer numbers to specify the digits, I want to insert the user's number in that process. Something like echo %var:~0,%number%%.
Is that possible? Or is there any other way I could do this?
Variables (with the exception of command line arguments) in batch is wrapped around with %, so you can't write %var:~0,%number%% because the variable ends at the first % and results in syntax error
You need to use delayed expansion
setlocal EnableDelayedExpansion
for /f "delims=" %%x in (TEXTFile.txt) do set var=%%x
set /p number="Input number: "
echo !var:~%number%,1!
Assuming you had the line of text you want as a variable line, you could do something like
#echo off
set number=3
set line=AJS12U3254FU8AD
for /l %%i in (%number%,1,%number%) do (
call set character=%%line:~%%i,1%%
)
echo %character%
A different method to force delayed expansion (which doesn't conflict with exclamation marks in the variable) is using a pseudo call.
The call forces another parsing of the line.
The first pass resolves the %number% while the doubled %% are reduced to a single one.
The second pass resolves the now single %.
#Echo off
Set "var=AJS12U3254FU8AD"
set /p "number=Enter a number:"
Call echo %%var:~%number%,1%%

for loop in batch script increment two or more variables

Yeah, batch scripting. I know. Sorry.
The final goal is to produce a file containing XML elements. Up to now, these items have been created by hand, but there's got to be a better way. My first idea is to do a batch script. What I've been doing up until now is copy/ paste, manually adding +1 to the id, page, and src="page_#" items. It's fine when the xml file contains only 40 entries. Not so fine when we're going past 100 or more.
GOAL: Need to increment the elements, say, navPoint id=#, Page #, and content src=page_# in the below:
<navPoint id="1"><text>Page 1</text><content src="page_1.html"></navPoint>
I've got a working batch script that can loop and update ONE variable, and it is thusly:
echo
for /l %%x in (1, 1, 8) do (
echo ^<navPoint id="navPoint-%%x"^>^<navLabel^>^<text^>Page %%x^</text^>^</navlabel^>^<content src="page_%%x.html"/^>^</navPoint^>)>>C:\Users\me.txt
This last part, >>C:\Users\me.txt, sends it to a txt file.
HOWEVER, I want the Page number to start at 2, not 1. My batch script works great, %%x starts at 1 and increments uniformly. I need another variable in the loop that is one greater than %%x.
so the result would be:
<navPoint id="1"><text>Page 2</text><content src="page_1.html"></navPoint>
and the next result would be:
<navPoint id="2"><text>Page 3</text><content src="page_2.html"></navPoint>
etc...
How can this be accomplished in batch scripting? I thought it would be as simple as %%x+1 but it's not...
You can do arithmetic with set /a. Do help set from the command line to read about it.
If you set a variable inside a block (e.g., if, for), you need to enable delayed variable expansion with setlocal EnableDelayedExpansion. Then you use ! instead of % to expand the variable. If you are outside of the code block, you can go back to using %. help set also will tell you about delayed expansion.
Using these 2 pieces of information, you can change your code to this to get what you want:
#echo off
setlocal EnableDelayedExpansion
for /l %%x in (1, 1, 8) do (
set /a PAGENUM=%%x+1
echo ^<navPoint id="navPoint-%%x"^>^<navLabel^>^<text^>Page !PAGENUM!^</text^>^</navlabel^>^<content src="page_%%x.html"/^>^</navPoint^>
)>>C:\Users\me.txt

Resources