batch file to swap out info between two files - batch-file

I need help with a batch file to do the (I suppose simple) task of reading info from a master file between two "tags" and overwriting current info in other file with the info from this master file.
Here is my situation as a simple example:
I have a file called "template.htmltplt" that is my master file if you will. Then I have a bunch of other ".html" files.
I would like the batch file to:
Go through all the html files
Delete all the lines between <!--Stuff-Start--> and <!--Stuff-End-->
Copy the content between the <!--Stuff-Start--> and <!--Stuff-End--> tags in the template.htmltplt into their correct place in the other html files.
Is this even possible and if so how?!
I have NO bat script knowledge so well commented code would be awesome!
Thanks in advance for those willing to help!
Regards,
Reinhardt

#ECHO Off
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "startstring=<!--Stuff-Start-->"
SET "endstring=<!--Stuff-End-->"
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
(
SET "block="
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r "^" q23715314.txt') DO (
IF "%%b"=="%endstring%" SET "block="
IF DEFINED block ECHO(%%b
IF "%%b"=="%startstring%" SET block=Y
)
)>"%tempfile%r"
FOR /f "delims=" %%t IN ('dir /b /a-d %sourcedir%\*.html') DO (
SET "block="
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r "^" "%sourcedir%\%%t"') DO (
IF "%%b"=="%endstring%" SET "block="
IF NOT DEFINED block ECHO(%%b
IF "%%b"=="%startstring%" SET block=Y&TYPE "%tempfile%r"
)
)>"%destdir%\%%~nt.html"
del "%tempfile%*"
GOTO :EOF
Not hard.
I used a file named q23715314.txt containing this data for my testing:
drop <this> line
<!--Stuff-Start-->
Insert this
and this
and even <this> line after an empty line
<!--Stuff-End-->
omit this
leave this out
And test .html file:
leave <this> line
empty line retained
<!--Stuff-Start-->
Replace this
replace this too
and substitute for <this> line
<!--Stuff-End-->
keep this
retain this too
resultant new .html file:
leave <this> line
empty line retained
<!--Stuff-Start-->
Insert this
and this
and even <this> line after an empty line
<!--Stuff-End-->
keep this
retain this too
Naturally, you'd need to set your own file and directory names, and I'd advise strongly against trying to use the same directory for the source and destination. That won't work at all. And any .html source line that starts with one or more colons will have those colons stripped-out - not that many .html lines start with colons, but it needs to be said...
How it works - block by block.
The first part would seem obvious. The directories involved are defined and the target strings, too.
Next there's a create-a-tempfile routine. Simply generate a random filename and see whether there is an existing matching filename in directory %temp%. Personally, I set up temp to be c:\temp but the code is designed to use the default. So, if the random-number generator chooses 18749 then the code looks for any file 18749... in the temporary directory. If such a file exists, then choose another random number. If it doesn't create a file named 18749a in the temporary directory. This is simply a placeholder.
Next step is to extract the required lines to a temporary file. the (block of code)>filename syntax directs any data echoed to a new file in filename - which should contain the full filename of a valid file in the temporay directory; for example c:\temp\18749r.
The code within the block first sets block to empty, then reads the file q23715314.txt line-by-line, numbering each line by prefixing it with number:. This ensures that empty lines are processed as 13:, otherwise they'd be skipped. The q23715314.txt isn't significant - it can be any file containing the required template data. I simply use qSOquestionnumber.extension in order that I can keep the data in files related to the batch file I write (called qSOquestionnumber.bat) - so the many questions using file1 and file2 can be easily individually retrieved in the case of a problem. The temporary file could be any valid filename you like, if you want to have a fixed filename. Note however that filenames containing spaces and some other symbols will need to be "quoted".
Since each line is processed by the for as it it was number:linefromfile then using tokens=1*delims=: will assign the number to %%a and linefromfile to %%b.
The block processing simply matches the line that was read from the file to the start/end string defined. block was originally "set" to empty, so it is undefined. When the startstring is matched, block is assigned a value. I used Y, but any value will do.
When the for reads the next string from the file, it finds that block is now defined, so it echoes %%b to the file c:\temp\18749r. This continues until endstring is found, when block is "set" to empty again; hence it is undefined and there is no more echoing to c:\temp\18749r.
The inner for of the second block is similar, but reversed. It reproduces each line from the file selected in the outer loop until the startstring is found, then types the contents of the tempfile and waits for the endstring when it clears blockand hence turns onthe echoing again.
The outer loop simply reads dir /b /a-d for the source directory - a directory list of simply the filenames. The "delims=" assigns the entire line to %%t and hence the outer loop is for...%%t...do (innerblock)>"%destdir%\%%~nt.html" which redirects the data echoed by the inner loop to the file with the name part of %%t (%%~nt) with the destination directory specified and the extension .html
Finally, the tempfiles are deleted.

You can't do that with a batch file. Use visual basic or pearl for something like that. Closest a batch file could do to something like that is have the output from one file be used as the input for another file but that's as specific wait can get.
Lottopix.has > prevwinum.cgi

Related

how to loop files in a folder which has space in it

I have the following code to copy files from a list. When the path of the files which the folder name has no space, it works perfectly. But the folder names could have space sometimes, how can I improve the code to handle the folder name with space
FOR /F %%a in (find_file_list.txt) DO COPY "%%a" "C:\test\%%~nxa"
Basically, in this find_file_list.txt, there list all files with path
c:\abc\def\12345.txt
c:\abc\def\12346.txt
c:\abc\def\12347.txt
the above code copy all these three files into folder of test and works fine.
Now when find_file_list.txt change, actually the real folder name has space in it, like
c:\ab c\de f\12345.txt
c:\ab c\de f\12346.txt
c:\ab c\de f\12347.txt
the above code not working anymore...
any thoughts?
You forgot to select the delims you want to split on:
FOR /F "delims=" %%a in (find_file_list.txt) DO COPY "%%a" "C:\test\%%~nxa"
Default delimeters are whitespace, if your file contains it, it will split on the whitepace.
Simply add "delims=" to change it to take the full string.
To output each non empty line in the file, you should ensure that you stipulate either all tokens or no delimiters, (you may also need, depending upon your task, to prevent the exclusion of lines beginning with a specific character, the default For behavior is to ignore all lines which begin with a semicolon, ;).My preference in this instance is to stipulate all tokens; this, unlike stipulating nodelimiters, will remove all leading whitespace from every line, (this would prevent files carrying accidental leading spaces from being picked up).
You cannot copy a file which does not exist, you could supress any error when trying to do so by using 2>Nul, but I would consider it better practice to see if the file exists first.
When you copy a file you need provide only the destination, (you only need to provide the file name if you're changing it).
Instead of using the Copy command you could instead use the XCopy command, this has the benefit of creating the destination directory, (subject to permissions), if it doesn't already exist.
Here therefore is a batch file example:
#For /F UseBackTokens^=*EOL^= %%A In ("find_file_list.txt") Do #If Exist "%%A" XCopy "%%A" "C:\test\">Nul
…and a very slightly modified version to be run from the Command Prompt:
For /F UseBackTokens^=*EOL^= %A In ("find_file_list.txt") Do #If Exist "%A" XCopy "%A" "C:\test\">Nul

Have batch edit a .txt file contents

I have a large grouping of text files that have the basic pattern of
Files 1 Header
1. Data
2. Data
3. Data
My hope is to run a batch that will read it in and remove the 1st line and the three characters of the remaining lines and output like below.
Data
Data
Data
Tried building a loop to grab each line and then put it through %line:~3%but its not working as excepted and I'm not sure how to remove the first line of the text file to begin with.
Any help would be greatly appreciated.
for %%a in (*.txt) do for /f "skip=1usebackq tokens=1*" %%t in ("%%a") do >>%%~na.new echo %%u
Put each filename matching *.txt into %%a then read each line of the file, skipping the first, and tokenise on the first space (default delimiter), outputting the second (* token = rest-of-line) token by appending to filename samenameastextfile.new (%%~na.new)
This should create a new set of files with the processed results.
It looks like you want to process CSV files with removing header line and first data column containing just the row number.
This batch code might be the right one for your file reformatting task:
#echo off
for /F "delims=" %%I in ('dir * /A-D /B 2^>nul') do (
for /F "usebackq skip=1 tokens=1*" %%A in ("%%~I") do echo %%B>>"%%~nI.tmp"
move /Y "%%~nI.tmp" "%%~I"
)
The outer loop runs command DIR to get a list of file names in current directory and processes each file name from this list independent on what happens with the files in current directory while running the loop.
The inner loop processes each line from current file with the exception of first line because of skip=1. The lines are split up because of tokens=1* into two strings:
the number with the point being assigned to loop variable A, and
everything else from line after the spaces/tabs after number and point being assigned to next loop variable B.
The string assigned to loop variable B is output with command ECHO and redirected into a temporary file with same name as current file, but file extension tmp.
After processing all lines of current file, the temporary file is moved over the current file to replace it, i.e. delete current file and rename temporary file to name of current file.
Note 1: The files in current directory should not have the file extension tmp as in this case the batch code would not work.
Note 2: The batch file should not be in current directory with the files to modify or something other than * is used on DIR command line which excludes the batch file for being also processed.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
for /?
move /?
Read also the Microsoft article about Using Command Redirection Operators.

Renaming multiple files in a for loop with user input Windows batchfile

I want to create a program that can loop through multiple pdf files and have the user rename each file a unique name like so:
234324.pdf to Batch150.pdf
32154687.pdf to AdvancedPayment.pdf
and so on...
Here is my code:
setlocal EnableDelayedExpansion
echo rename pdf files
FOR %%F IN (*.pdf) DO (
set /p x=Enter:
move %%F !x!
)
endlocal
This seems to work for the first file and then when I try to rename the second one it says: The syntax of the command is incorrect..
I have tried using the rename command and haven't had much luck with it.
FOR %%F IN (*.pdf) DO (
SET "x=%%F"
set /p "x=%%F Enter: "
IF /i "!x!.pdf" neq "%%F" ren "%%F" "!x!.pdf"
)
Your code worked fine for me. Since you don't indicate what the "to" and "from" names you used were, we're reduced to guessing.
I developed the above code to perform the rename in the manner you originated. Note that it works as I expect. Using ren the "to" filename must be a filename within the directory where the "from" file resides [ie. it simply renames the file]. If you use "move" then the file can be moved to another directory if you specify that in the "to" name.
The first fix is purely cosmetic. By enclosing the variablename and prompt in the set /p in quotes, you can include a terminal space in the prompt (which I prefer), and including the %%F in the prompt shows you which file is about to be renamed.
The next fix is to quote the arguments to the ren or move. This ensures the syntax remains properly constructed in the case of eithr "to" or "from" name containing a space.
The next is to initialise x with the "from" filename. It's enclosed in quotes so any invisible trailing spaces are not included in the value assigned to x. Note that set /p does not alter the variable if Enter alone is keyed, so setting x ensures that if a file is not to be renamed, all you need do is press Enter
The next is to detect whether the "to" and "from" names are equal. ren will generate an error report if you attempt to rename a file to itself; equally, you can't move a file to itself. Hence, /i=ignore case, and only attempt the operation if the names are different.
Finally, add the .pdf to each usage of !x! in order that you don't need to key it in. Naturally, you could omit this change if you want to alter extensions or you could put .pdf into another variable and use that variable in place of the constant .pdf so that the extension being selected can be easily varied by being changed in one plaace rather than using a mass-edit. You could even use a set /p to assign the extension being processed dynamically at the start of the routine.
Note that if you rename say one.pdf to yellow.pdf then this construct is very likely to propose yellow.pdf for a rename later on. This is because the next-filename logic locates the next filename currently in the directory,then processes the loop, then locates the next filename currently in the directory, and so on.
You would need
For /f "delims=" %%F in ('dir /b/a-d "*.pdf" ') do (
to ensure that each filename is only presented once. This mechanism performs a directory scan of filenames-only in basic form, and stores the list in memory, then processes the list item-by-item and since that list is created and then processed, any subsequent alterations to the directory do not affect the list.

Read a file in batch

I am creating a small batch application and I would like to know how to to put file contents into variables or wildcards. (Don't know which one it is) I used to be able to do "set blablabla=< MainChat.txt" but it is not working. It would be very helpful if someone could tell me how to load one line of a file into a variable, and the next line into another.
read file line by line including empty lines -> http://www.dostips.com/forum/viewtopic.php?p=9611
-OR-
processing text file:
for /f "useback tokens=* delims=" %%# in ("c:\text.file") do (
set "current_line=%%#"
)
more info here: http://ss64.com/nt/for_f.html

Use Dos commands to copy file and preserve date in file name

I'm having trouble trying to copy and rename a file using only dos commands. I have a file of the format myfile20130218 and want to copy and rename it to some_other_file_20130218.
I know I can use copy source dest but I'm having trouble with how to isolate the date and preserve it. I cannot guarantee that he date will be today's date so that is ruled out, the source file will always be the same name.
I can run either a series of commands or a batch script, but thing that that I am currently having trouble with, is after I find a match that I need to copy, using myfile????????, how can I now get those file names to pull the dates off them?
EDIT: for clarification I will be looking at files in a known directory, as above, I will know the format of the file name, and will only be checking a specific directory for it. The process that checks the directory is a ConnectDirect file watcher, so when a file is found matching myfile20130218 I can fire off some commands, but don't know how to check the directory and get the name of the file present.
Something like this should work:
%oldname:~-8% extracts the last 8 characters from %oldname% which are then appended to the new filename.
Update: If you can identify the file with an external program and then call the batch script with the file name
copyfile.cmd C:\path\to\myfile20130218
you could do something like this:
set oldname=%~nx1
set newname=%~dp1some_other_file_%oldname:~-8%
copy "%~f1" "%newname%"
Update 2: If you know folder and the format you could call the script with the folder
copyfile.cmd C:\folder
and do something like this:
#echo off
setlocal EnableDelayedExpansion
for /f %%f in (
'dir /b "%~f1" ^| findstr /r "myfile[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$"'
) do (
set oldname=%~f1\%%f
set newname=%~f1\my_other_name_!oldname:~-8!
copy "!oldname!" "!newname!"
)
endlocal
Edit: Script breakdown.
setlocal EnableDelayedExpansion enables variable expansion inside loops and conditionals.
for /f %%f in ('...') executes the command between the single quotes and then loops over the output of that command.
dir /b "%~f1" lists the content of the given directory (%~f1 expands to the full path of the first argument passed to the script) in simple mode (no header, no summary).
findstr /r "myfile[0-9]...[0-9]$" filters the input for strings that end with the substring "myfile" followed by 8 digits. The circumflex before the pipe (^|) escapes the pipe, because otherwise it would take precedence over the for command, which would effectively split the for command in half, resulting in an invalid command-line.
set oldname=%~f1\%%f assign the full path to a matching file to the variable oldname.
set newname=%~f1\my_other_name_!oldname:~-8! assign the full path to the new filename ("my_other_name_" followed by the trailing 8 digits from oldname) to the variable newname.
copy "!oldname!" "!newname!" I don't need to explain this, do I?

Resources