compare two files using batch script - batch-file

I've two files
file 1:
PROCESS_NAME
wf_1
wf_2
wf_3
file 2:
wf_1 - [Running]
wf_2 - [Succeeded]
wf_2 - [Succeeded]
So now I need to compare the above two files and have to remove the names in file1 for which the status in file2 is [Succeeded]. Struggling for hte past 3 days.
Result should be
file 1:
wf_1
Appreciate any help.

Here you go
#echo off
setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (file1.txt) do (
for /f "skip=1 tokens=*" %%b in ('find "[Succeeded]" file2.txt') do (
set check=%%b
set check=!check: - [Succeeded]=!
if "%%a"=="!check!" set bool=true
)
if not "!bool!"=="true" echo %%a >>new.txt
)
del file1.txt /f /q
ren new.txt file1.txt
Just replace file1.txt and file2.txt with your actual file names.

Const ForReading = 1
Const TextCompare = 1
Dim File1, File2, OutputFile
File1 = "D:\1t\test1\ddir11.txt"
File2 = "D:\1t\test1\ddir12.txt"
OutputFile = "D:\1t\test1\outfile.txt"
Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
If ObjFSO.FileExists(File1) Then
Dim objFile1 : Set objFile1 = objFSO.OpenTextFile(File1, ForReading)
Else
WScript.Quit
End If
' Dictionary object for reference file.
Dim RefDict : Set RefDict = CreateObject("Scripting.Dictionary")
RefDict.CompareMode = TextCompare
Dim StrLine, SearchLine, strNotFound
' Read reference file into dictionary object.
Do Until objFile1.AtEndOfStream
StrLine = Trim(objFile1.ReadLine)
'MsgBox (StrLine)
if Not RefDict.Exists(StrLine) Then
RefDict.Add StrLine, "1"
End If
Loop
Dim a,s,i
a = RefDict.Keys
'read dictionary....
'For i = 0 To RefDict.Count -1 ' Iterate the array.
' s = s & a(i) & "<BR>" ' Create return string.
'Next
objFile1.Close
' File that may have more or less lines.
If ObjFSO.FileExists(File2) Then
Dim objFile2 : Set objFile2 = objFSO.OpenTextFile(File2, ForReading)
Else
WScript.Quit
End If
' Search 2nd file with reference file.
Do Until objFile2.AtEndOfStream
SearchLine = Trim(objFile2.ReadLine)
If Not RefDict.Exists(SearchLine) Then
If IsEmpty(strNotFound) Then
strNotFound = SearchLine
Else
strNotFound = strNotFound & vbCrlf & SearchLine
End If
End If
Loop
objFile2.Close
If IsEmpty(strNotFound) or strNotFound = "" Then
End If
Dim objFile3 : Set objFile3 = objFSO.CreateTextFile(OutputFile, True)
MsgBox ("str:" & strNotFound)
objFile3.WriteLine strNotFound
objFile3.Close

Related

Multiple find and replace operations in a single batch

I need to do multiple find and replace operation on a single file. The setup is as follows:
Text data - File.txt
Replacement data - File2.txt
The structure of File2.txt is like this:
ABC,XYZ
MNB,OPI
GHI,TRY
The first column is my original name (eg. ABC) and replaced with the 2nd name (eg. XYZ). This has to be done in the original File.txt
I can write a code to do a single change or to increment the name from ABC to ABC_Date but I am confused about how to loop and read both to and from names.
Any help is appreciated.
I was able to solve this by gluing together answers from:
How can you find and replace text in a file using the Windows command-line environment?
How do you loop through each line in a text file using a windows batch file?
The code is:
for /F "tokens=1,2,3" %%i in (myfile.txt) do call :process %%i %%j %%k
goto thenextstep
:process
#echo %1
#echo %2
cscript replace.vbs "C:\newfile.txt" "%1" "%2"
goto :EOF
replace.vbs
Const ForReading = 1
Const ForWriting = 2
strFileName = Wscript.Arguments(0)
strOldText = Wscript.Arguments(1)
strNewText = Wscript.Arguments(2)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(strFileName, ForReading)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, strOldText, strNewText)
Set objFile = objFSO.OpenTextFile(strFileName, ForWriting)
objFile.Write strNewText 'WriteLine adds extra CR/LF
objFile.Close
Here, This is the sample powershell code to replace multiple words from another file. You have to change the $file1Text value and $file2Text value
$file1Text = "this is sample text. You have to get the text from file" ; # your file1 data
$file2Text = "this,here it","text,data","file,physical file" # your file2 lines
$finalText = $file1Text ; # Temp variable [ optional ] : you can use file1Text directly
foreach ($str in $file2Text)
{
$split = $str.Split(',')
$find = $split[0]
$replace = $split[1]
$finalText = $finalText.Replace($find,$replace)
}
cls
"Original Text : " + $file1Text
"Replaced Text : " + $finalText

batch find and replace

this is my problem:
on a Windows 2003 server I've a folder (c:\test), and every day an application put 3 new files on it.
1° file:
31201610181207000100000000630001
31201610181213000100000000440001
31201610181227000100000000630001
....
2° file:
31201610181214000100000000380002
31201610181234000100000009830002
31201610181344000100000000380002
...
3° file:
31201610181826000100000000580003
31201610190722000100000000580003
31201610191801000100000000580003
...
My goal is to replace ONLY the last 4 characters on each file with a .bat or .vbs script (0001 --> 0031) (0002 --> 0032) (0003 --> 0033).
I've done a .vbs file who works, but it search on all string and not on the last 4 characters.
Option Explicit
Dim objFSO, strFolder, objFolder, objFile
Dim strOldValue1, strNewValue1, strNewValue2, strOldValue2, strNewValue3,
strOldValue3, objRead, strContents, objWrite
Const ForReading = 1
Const ForWriting = 2
strFolder = "c:\test"
strOldValue1 = "0001"
strNewValue1 = "0031"
strOldValue2 = "0002"
strNewValue2 = "0032"
strOldValue3 = "0003"
strNewValue3 = "0033"
' I take the folder
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strFolder)
' I count the file on the folder
For Each objFile In objFolder.Files
' Read file with textstream object.
Set objRead = objFSO.OpenTextFile(objFile.Path, ForReading)
' Trap error if file is empty or cannot read.
On Error Resume Next
strContents = objRead.readall
If (Err.Number <> 0) Then
On Error GoTo 0
Wscript.Echo "Cannot read: " & objFile.Path
strContents = ""
End If
On Error GoTo 0
objRead.Close
' check what's is inside the folder
If (InStr(strContents, strOldValue1) > 0) Then
strContents = Replace(strContents, strOldValue1, strNewValue1)
Set objWrite = objFSO.OpenTextFile(objFile.Path, ForWriting)
objWrite.Write strContents
objWrite.Close
End If
If (InStr(strContents, strOldValue2) > 0) Then
strContents = Replace(strContents, strOldValue2, strNewValue2)
Set objWrite = objFSO.OpenTextFile(objFile.Path, ForWriting)
objWrite.Write strContents
objWrite.Close
End If
If (InStr(strContents, strOldValue3) > 0) Then
strContents = Replace(strContents, strOldValue3, strNewValue3)
Set objWrite = objFSO.OpenTextFile(objFile.Path, ForWriting)
objWrite.Write strContents
objWrite.Close
End If
next
Thanks for any help!!
Here is a short batch script, which immediately modifies all files C:\test\*.* accordingly:
for %%F in ("C:\test\*.*") do (
for /F "delims=" %%L in ('type "%%~F" ^& ^> "%%~F" rem/') do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LEFT=!LINE:~,-4!"
set "RIGHT=!LINE:~-4!"
if "!RIGHT!"=="0001" set "RIGHT=0031"
if "!RIGHT!"=="0002" set "RIGHT=0032"
if "!RIGHT!"=="0003" set "RIGHT=0033"
>> "%%~F" echo(!LEFT!!RIGHT!
endlocal
)
)
Using JREPL.BAT - a regular expression find/replace utility
for %%F in (c:\test\*) do call jrepl "000(?=[123]$)" "003" /f "%%F" /o -
The above looks at the end of each line for "000" before a "1", "2", or "3", and substitutes "003" for the "000".
JREPL is pure script (hybrid batch/JScript) that runs natively on any Windows machine from XP onward - No 3rd party exe file required.
Thank you very much!!!! it works!!
Also, if you're interested I've found how the make my script work:
I've to add the & VBCrlf to the variable, in this way the script will search for the value + the new line.
strOldValue1 = "0001" & VBCrlf
strNewValue1 = "0031" & VBCrlf
strOldValue2 = "0002" & VBCrlf
strNewValue2 = "0032" & VBCrlf
strOldValue3 = "0003" & VBCrlf
strNewValue3 = "0033" & VBCrlf

how to loop through folders specified by text document on batch script

I have a list of folder paths that I want to loop through and get the files and creation date and then send a email notification that these files have been uploaded to the ftp. I have got everything working but I am having trouble looping through the folders to get the files. I think it loops through the text file but by the time i get to my second loop I think it is only looping through the last path that was in the text doc as the variable was getting overwritten. I tried enclosing the second for statement with parentheses for the first for statement but did not work. Here is my code:
scanFTPCLients.bat
#echo off
setlocal EnableDelayedExpansion
cls
#pushd %~dp0
set i=0
for /F "tokens=*" %%i in (Pathlist.txt) do (
set fp=%%i
set LIST=
for /r "%fp%" %%a in (*.*) do set i=i+1
set LIST=!LIST! ---%deptClient%--- %%~na ----UPLOAD TIME---- %%~ta
)
set LIST=%LIST:~1%
IF %i% NEQ 0 (wscript "%~dp0FTPFilesUploadedNotification.vbs")
popd
Pathlist.txt
\\vavm\CINICO\Incoming
\\vavm\CIS\Incoming
\\vavm\Forcht\Incoming
\\vavm\HPC\Incoming
\\vavm\K\Incoming
\\vavm\MWEmpCC\Incoming
\\vavm\National Labor Benefits\Incoming
\\vavm\PeriSons\Incoming
\\vavm\US\Incoming
\\vavm\K\Incoming
FTPFilesNotification.vbs
dim outputArray
dim inputText
dim message
inputText = CreateObject("WScript.Shell").ExpandEnvironmentStrings("%LIST%")
outputArray = split(inputText, " ")
for each x in outputArray
message = message & x & vbCRLF
next
Set MyEmail=CreateObject("CDO.Message")
MyEmail.Subject="Clients Imported to System"
MyEmail.From="SYSTEMFUNCTION#mrsllc.org"
MyEmail.To="rickg#gmail.com"
MyEmail.TextBody= "The Following Clients have been imported to the system: " & vbCRLF & message
MyEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing")=2
MyEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver")="mail.org"
MyEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport")=25
MyEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate")=1
MyEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusername")="username"
MyEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendpassword")="password"
MyEmail.Configuration.Fields.Update
MyEmail.Send
set MyEmail=nothing
For comparison, in PowerShell, it could be:
$emailSettings = #{
From = "you#example.org"
To = "you#example.org"
Subject = "Upload report"
SmtpServer = "yourmailserver"
}
$report = dir -Path #(gc pathlist.txt) | select FullName, CreationTime
Send-MailMessage #emailSettings -Body "$($report|ConvertTo-Html)" -BodyAsHtml
This shows how to loop through files in vbscript
'On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
Dirname = InputBox("Enter Dir name")
'Searchterm = Inputbox("Enter search term")
ProcessFolder DirName
Sub ProcessFolder(FolderPath)
On Error Resume Next
Set fldr = fso.GetFolder(FolderPath)
Set Fls = fldr.files
For Each thing in Fls
' Set contents = thing.OpenAsTextStream
' If err.number = 0 then
' If Instr(contents.readall, searchterm) > 1 then msgbox thing.path
' Else
' err.clear
' End If
msgbox Thing.Name & " " & Thing.DateLastModified
Next
Set fldrs = fldr.subfolders
For Each thing in fldrs
ProcessFolder thing.path
Next
End Sub
To send mail
Set emailObj = CreateObject("CDO.Message")
emailObj.From = "dc#gail.com"
emailObj.To = "dc#gail.com"
emailObj.Subject = "Test CDO"
emailObj.TextBody = "Test CDO"
Set emailConfig = emailObj.Configuration
msgbox emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver")
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.gmail.com"
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 465
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = true
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/sendusername") = "YourUserName"
emailConfig.Fields("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "Password1"
emailConfig.Fields.Update
emailObj.Send
If err.number = 0 then Msgbox "Done"
To read a file line by line
On Error Resume Next
Set Fso = CreateObject("Scripting.FileSystemObject")
Set File = Fso.CreateTextFile("C:\myfile.txt", True)
If err.number <> 0 then
Wscript.Echo "Error: " & err.number & " " & err.description & " from " & err.source
err.clear
wscript.exit
End If
Do Until File.AtEndOfStream
Msgbox File.readline
Loop
Changed. Not sure what you want to do about sending lines (one at a time or send all when done). If one at a time, integrate into this. If all at once at end, then send output to a temp file and send it.
#echo off
pushd %~dp0
set /A Cnt=0
for /F "tokens=*" %%i in (Pathlist.txt) do (
echo i= %%i
for /f "usebackq tokens=*" %%a in (`Dir /s /b %%i\*.*`) do (
echo %%~na - %%~ta
set /A Cnt+=1
)
)
echo(Cnt=%Cnt%
pause
popd

Making Batch file code with VBScript to work with Unicode symbols

So recently I asked for help with creating .srt subtitles. Here is the link.
I got the help and everything works fine until the videofile in the folder has unicode symbols in its name. If it does, then VBScript error appears. Question is how to make this code work correctly with Unicode symbols.
Here is the code:
#echo off&cls
::The Path of your Videos files
set "$VideoPath=C:\FolderwithVideos"
::If you want your Code in this BAT remove the REMs Below :
rem dir "%$VideoPath%" /O:S /b /-p /o:gn > "C:\result.txt"
rem call replacer.bat result.txt ".mp4" ""
setlocal enabledelayedexpansion
set /a $Count=1
set "$Timer=00:00:00"
(for /f "delims=" %%a in (result.txt) do (
call:getVideolength "%%a.mp4"
for /f "delims=" %%x in ('cscript //nologo getvideolength.vbs') do (
call:SumTime !$Timer! %%x
for /f "delims=" %%y in ('cscript //nologo SumTime.vbs') do set "$NewTimer=%%y"
echo !$Count!
echo !$Timer!,000 --^> !$NewTimer!,000
echo %%a
Set $Timer=!$NewTimer!
)
set /a $Count+=1
echo.
))>Output.srt
echo Done !!!
type Output.srt
pause
exit/b
:GetVideoLength
(echo dim objShell
echo dim objFolder
echo dim objFolderItem
echo set objShell = CreateObject("shell.application"^)
echo set objFolder = objShell.NameSpace("%$videoPath%"^)
echo set objFolderItem = objFolder.ParseName(%1^)
echo dim objInfo
echo objInfo = objFolder.GetDetailsOf(objFolderItem, 27^)
echo wscript.echo objinfo)>GetVideoLength.vbs
exit/b
:SumTime
echo wscript.echo FormatDateTime(CDate("%1"^) + CDate("%2"^),3^) >SumTime.vbs
exit/b
After reviewing the previous question I merged all the code and logic into one unicode safe VBScript file.
Option Explicit
Const adUnsignedBigInt = 21
Const adVarWChar = 202
Const adVarChar = 200
Dim VideoDir
VideoDir = "C:\FolderwithVideos"
'or from a script argument when called like : cscript script.vbs "C:\FolderwithVideos"
'VideoDir = WScript.Arguments(0)
Const adSaveCreateOverWrite = 2
Const adCRLF = -1
Const adWriteLine = 1
Dim ShellApp
Set ShellApp = CreateObject("Shell.Application")
Dim Fso
Set Fso = CreateObject("Scripting.Filesystemobject")
Dim VideoExts
Set VideoExts = CreateObject("scripting.dictionary")
VideoExts.CompareMode = vbTextCompare
VideoExts.Add "mp4", Null
'add more extensions if you need
'VideoExts.Add "srt", Null
'VideoExts.Add "mkv", Null
Dim SrtStream
Set SrtStream = CreateObject("Adodb.Stream")
SrtStream.Charset = "utf-8"
SrtStream.Open
Dim Folder, IFolderItem, VideoCount, OldDuration, NewDuration, FileExtension, SrtPath, RsSorted
Set RsSorted = CreateObject("Adodb.Recordset")
RsSorted.Fields.Append "Name", adVarWChar, 255
RsSorted.Fields.Append "Size", adUnsignedBigInt
RsSorted.Fields.Append "Duration", adVarChar, 8
RsSorted.Open
NewDuration = TimeSerial(0,0,0)
Set Folder = ShellApp.NameSpace(VideoDir)
For Each IFolderItem In Folder.Items
FileExtension = Fso.GetExtensionName(IFolderItem.Name)
If VideoExts.Exists(FileExtension) Then
RsSorted.AddNew Array("Name", "Size", "Duration"), Array(IFolderItem.Name, IFolderItem.Size, Folder.GetDetailsOf(IFolderItem, 27))
End If
Next
RsSorted.UpdateBatch
RsSorted.Sort = "Size, Name"
If Not RsSorted.BOF Then RsSorted.MoveFirst
While Not RsSorted.EOF And Not RsSorted.BOF
FileExtension = Fso.GetExtensionName(RsSorted("Name").Value)
VideoCount = VideoCount + 1
OldDuration = NewDuration
NewDuration = OldDuration + CDate(RsSorted("Duration").Value)
SrtStream.WriteText VideoCount, adWriteLine
SrtStream.WriteText OldDuration & ",001 --> " & NewDuration & ",000", adWriteLine
SrtStream.WriteText Left(RsSorted("Name").Value, Len(RsSorted("Name").Value) - (Len(FileExtension) + 1)), adWriteLine
SrtStream.WriteText "", adWriteLine
RsSorted.MoveNext
Wend
SrtPath = Fso.BuildPath(VideoDir, "Output.srt")
SrtStream.SaveToFile SrtPath, adSaveCreateOverWrite
SrtStream.Close
WScript.Echo "Done!"
WScript.Echo SrtPath

Best way to read and split the large file to multiple small files

I have XML file with >100MB (more than 20L lines) and I cannot pass it directly to my one of the process. I need to split in to multiple smaller files by assuming some separator and I tried using FileSystemObject in VBScript as well as BATCH file option. Both takes more than 8 mins to read and create first small file with 10000 lines.
Please convey some good performance oriented options for this task.
Appreciate your help.
Method1:
Function SplitXML()
Dim oSrcFile, oTgtFile, strHeader, intFiles, strContent, intSize
Dim arrLines()
Set oFSO = CreateObject("Scripting.FileSystemObject")
strFilePath = Application.GetOpenFilename
intLinesToSplit = InputBox("Enter the No of Lines to split with for each file:", "XML Splitter", 10000)
strTgtPath = Replace(strFilePath, oFSO.GetFileName(strFilePath), "")
strFileName = Replace(oFSO.GetFileName(strFilePath), ".xml", "")
Set oSrcFile = oFSO.OpenTextFile(strFilePath)
'Headers
strHeader = "": strContent = ""
Do
strTemp = oSrcFile.ReadLine
strHeader = strHeader & vbNewLine & strTemp
Loop While InStr(1, strTemp, "</BLHeader>", 1) <= 0
'Split
intTemp = 0: intFiles = 0: blnNewFile = True: intSize = -1
Do While Not oSrcFile.AtEndOfStream
intTemp = intTemp + 1
'Content
'intSize = intSize + 1
'ReDim Preserve arrLines(intSize)
'arrLines(intSize) = oSrcFile.ReadLine
strTemp = oSrcFile.ReadLine
strContent = strContent & vbNewLine & strTemp
If intTemp >= intLinesToSplit Then
If InStr(1, strTemp, "</EndingTag>", 1) > 0 Then
'Add Header
intFiles = intFiles + 1
Set oTgtFile = oFSO.CreateTextFile(strTgtPath & strFileName & "_" & intFiles & ".xml", True)
oTgtFile.WriteLine strHeader
'Add Content
oTgtFile.WriteLine strContent 'Join(arrLines, vbNewLine)
'Add tail
oTgtFile.WriteLine "</FinalFileTag>"
oTgtFile.Close
End If
End If
Loop
oSrcFile.Close
End Function
Method2:
#echo off
setlocal EnableDelayedExpansion
set InFile=c:\ee\EE28352646\in.txt
set OutDir=c:\ee\EE28352646
REM Can not be larger than 2147483648 !!!
set MaxLines=1000000
if not exist "%InFile%" (
echo *ERROR* Input file does not exist!
exit /b
)
if not exist "%OutDir%\" (
echo *ERROR* Output folder does not exist!
exit /b
)
for %%A in ("%InFile%") do (
set Name=%%~nA
set Ext=%%~xA
)
set /a Line=MaxLines+1
set File=0
for /f "usebackq tokens=*" %%A in ("%InFile%") do (
set /a Line+=1
if !Line! GTR %MaxLines% (
set /a File+=1
set OutFile=%OutDir%\%Name%_!File!%Ext%
if exist "!OutFile!" del "!OutFile!"
set Line=1
)
echo.%%A>>"!OutFile!"
)
The best way to split any XML file is -as always- to use an actual XML parser for the task. Assuming you have an XML file like this:
<?xml version="1.0"?>
<Foo>
<Bar>some</Bar>
<Bar>other</Bar>
</Foo>
and want to split it into separate files
<?xml version="1.0"?>
<Foo>
<Bar>some</Bar>
</Foo>
and
<?xml version="1.0"?>
<Foo>
<Bar>other</Bar>
</Foo>
you could do something like this:
numFiles = 4 'number of output files
Set src = CreateObject("Msxml2.DOMDocument.6.0")
src.async = False
src.load "C:\path\to\input.xml"
Set nodes = src.selectNodes("//Bar")
numNodes = nodes.length \ numFiles 'number of nodes per output file
Set xml = Nothing
For i = 0 To nodes.length - 1
'create a new XML object on the first iteration and every time numNodes
'nodes have been added to the current object
If i Mod numNodes = 0 Then
If Not xml Is Nothing Then
'if we already have an XML object: save it to a file
Set prolog = xml.createProcessingInstruction("xml", "version='1.0'")
xml.insertBefore prolog, xml.childNodes(0)
xml.save "C:\path\to\output" & (i \ numNodes - 1) & ".xml"
End If
Set xml = CreateObject("Msxml2.DOMDocument.6.0")
Set root = xml.createElement("Foo")
xml.appendChild root
End If
root.appendChild nodes.item(i)
Next
'save unsaved XML object
If Not xml Is Nothing Then
Set prolog = xml.createProcessingInstruction("xml", "version='1.0'")
xml.insertBefore prolog, xml.childNodes(0)
xml.save "C:\path\to\output" & (i \ numNodes - 1) & ".xml"
End If

Resources