I have a requirement to, within a windows batch file, read the first available line from a text file, pass it to a variable and mark the name\line as used
An example of the file is below.
apple
pear
orange
The script would start with 'apple', pass 'apple' to a variable to be used later in the script (I know how to do that bit), and then write back that line to read &apple, the '&' works as a marker to say it's been used.
The file would then look like:
&apple
pear
orange
the next time the batch file is run it would take 'pear', pass it to a variable and mark it with a & making it look like:
&apple
&pear
orange
I started by trying to find '&' and then trying to move to the next line, but I'm failing after about 12 hours of trying. This is what I got so far .. not much:
for /f "tokens=1" %l in ('name.txt') do (Find /v "&" /v "^---- ^$") (For /F %n in (%l) do (set NewName=%n))
Thanks
Running this on the.file
would modify each line in turn;
@echo off
setlocal enabledelayedexpansion
type nul > the.file.temp
set last=
for /F "tokens=*" %%A in (the.file) do (
set line=%%A
if "!line:~0,1!" neq "&" if "!last!" equ "" (
set last=!line!
set line=^&!line!
)
echo !line! >> the.file.temp
)
echo last value is !last!
type the.file.temp > the.file
(If the line does not begin with &
and the variable last
is empty, put the line in last
& modify line
with a leading &
. Always append line
to a temp file, renaming when done)
Alex k. has a good answer that is probably fine for most situations. (I upvoted.)
However, it will corrupt any text containing !
. That limitation can be fixed by toggling delayed expansion on and off within the loop.
The solution is likely to be fast enough for most reasonably sized files. But a FOR loop can become quite slow for large files.
I tested a 190kb file containing 2817 lines, and the Alex K. solution took 20 seconds for one run.
Here is a completely different solution without using any loops that processes the same 190kb file in 0.07 seconds - 285 times faster :)
@echo off
setlocal enableDelayedExpansion
set "file=test.txt"
findstr /bv "$ &" "%file%" >"%file%.available"
set "var="
<"%file%.available" set /p "var="
if defined var (
>"%file%.new" (
findstr /b "&" "%file%"
<nul set /p "=&"
type "%file%.available"
)
move /y "%file%.new" "%file%" >nul
)
del "%file%.available"
echo var=!var!
Update: As requested in comment, here is a heavily commented version of the code.
@echo off
setlocal enableDelayedExpansion
:: Define the file to process
set "file=test.txt"
:: Write the unused lines to a temporary "available" file. We don't want any
:: empty lines, so I strip them out here. There are two regex search strings;
:: the first looks for empty lines, the second for lines starting with &.
:: The /v option means only write lines that don't match either search string.
findstr /bv "$ &" "%file%" >"%file%.available"
:: Read the first available line into a variable
set "var="
<"%file%.available" set /p "var="
:: If var defined, then continue, else we are done
if defined var (
REM Redirect output to a "new" file. It is more efficient to redirect
REM the entire block once than it is to redirect each command individulally
>"%file%.new" (
REM Write the already used lines to the "new" file
findstr /b "&" "%file%"
REM Append the & without a new line
<nul set /p "=&"
REM Append the unused lines from the "available" file. The first appended
REM line is marked as used because of the previously written &
type "%file%.available"
)
REM Replace the original file with the "new" content
move /y "%file%.new" "%file%" >nul
)
:: Delete the temp "available" file
del "%file%.available"
:: Display the result
echo var=!var!
I haven't tested this, but I just realized I could have written the line that writes the available lines to look for lines that start with a character other than &
:
findstr "^[^&]" "%file%" >"%file%.available"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With