I have 1 task where there is 1 file start generating through DB and took almost 1 hour to generate, there is 1 batch file which check this file whenever it is available it calls a new batch file and trigger "file sent", the issue is that this file which is generating continuously did not completely generated at the file picked the same and call the batch file
What i want to do to build a logic where i can compare the size of file within a loop with 2 variable sizeA and sizeB, and call another batch file when sizeA==sizeB now the only issue is i am not sure how to built this logic in a code.\
Here is what I have tried:
#echo off
setlocal EnableDelayedExpansion
set file = "C:\Users\rb54761\Desktop\New folder\File.txt"
set "size=0"
pause
:loop for /f "tokens=*" %%x in ('dir /s /a /b "%file%"2^>nul') do set /a size=%%~zx
echo !size!
PAUSE
if !size! == !size! goto call
goto loop
:call echo Success
EDIT I only saw your comment now for being a 2gb file, then the below code will not work.
If the file were to be smaller..here is an example:
#echo off
set "myfile=C:\Users\rb54761\Desktop\New folder\File.txt"
:start
for /f %%I in ("%myfile%") do set size=%%~zI
if %size% LSS 100 (echo file not ready %size% & timeout /t 10 & goto :start)
echo copy file.
as per above, It will check the file for a size of 100kb, if not that size yet, it will timeout for 10 seconds and goto the beginning and test again until the file reaches 100kb, where it will no longer meet the if statement and pass that line and simply echo copy file.
Please note there are no spaces in my set commands. I would suggest you run from cmd the help for /? for more on this command.
We can use below approach in order to compare the size of same file within a span of time
#echo off
setlocal EnableDelayedExpansion
set file="d:\File_Mask1\New_File\File.txt"
set "size=0"
If exist %file% GOTO loop
GOTO nofile
:loop
for /f "tokens=*" %%x in ('dir /s /a /b %file%') do set /a size=%%~zx
echo !size!
waitfor SomethingThatIsNeverHappening /T 120 >nul 2>&1
for /f "tokens=*" %%y in ('dir /s /a /b %file%') do set /a size1=%%~zy
echo !size1!
if !size! EQU !size1! goto call
goto loop
:call
echo Success
endlocal
This takes advantage of the archive attribute. Windows sets this attribute each time it writes to the file.
So if we can unset it, wait for a time and check it (I use dir /aa which will not find the file, when the attribute is not set)
#echo off
set sec=10
set "file="C:\Users\rb54761\Desktop\New folder\File.txt""
set /a secs=sec+1
:loop
attrib -a "%file%"
timeout %sec% >nul
dir /b /aa "%file%" >nul 2>&1 || goto :loop
echo %file% didn't change since %secs% seconds
(Note: your set file = ... line is wrong. The spaces around the = will become part of the variable name respective the value)
Advantage: no file size limit (files bigger 2GB will be handled fine too)
Related
Sadly I couldn't yet manage find a working solution but hopefully this time.
Long story short, we got a printer and we are currently unable to configure the scanfolder to our network drives. So I need a script to rename and move the files but keep them all.
As far as I managed to come I got a smart idea to move the files into a firstfolder to avoid that the files are overwritten. Next I need to either rename the files with a counter or move them and keep them all.
I choose the rename option since this seems more simple but I ran into one big issue.
I have no idea how I make it work. So what I'm trying is to first set the variable and do a first test calculation. Just for a first quick test. Now it already works for the first count but sadly it doesn't count up as hoped since he does the rename for all the files before increasing the value of the variable so only one file is renamed.
#ECHO off
::Defining Variables
setlocal EnableDelayedExpansion
SET N=0
ECHO %N% Hi Not rename
SET /a N=%N%+1
FOR /L %%A in (1,1,10) DO (
Echo !N! hi
RENAME "C:\Users\smorheng\Desktop\1\*.pdf" "Test.?????.!N!.*" | SET /a N=!N!+1
ECHO !N! Hi Not rename
timeout 3 /nobreak > nul
)
ECHO RENAME DONE
timeout 50 /nobreak > nul
About 20 Files are renamed to something like Test.1.pdf, Test.2.pdf .... Test.20.pdf and then moved to their destination.
The moving is not an issue but if I could manage to get this feature working I can adapt it to whatever I need.
You can simply move the files, but first check if the file exists in destination, if it does, rename it using a numeric value after the name. Here is something that might work. You just need to change source and destination folder below. The actual move will not occur as I added echo to the second last and last line to demonstrate what it will do, if it works, simply remove echo from both lines.
#echo off
setlocal enabledelayedexpansion
set "source=C:\Users\smorheng\Desktop\1\"
set "dest=D:\destination\folder"
set /a cnt=0
for /f "tokens=*" %%a in ('dir /S /B /A-D "%source%*.pdf"') do for /f "tokens=*" %%b in ('dir /B "%%a"') do if exist "%dest%\%%b" (
set "ext=%%~xa"
set "fname=%%~na"
if exist "%dest%\!fname!(!cnt!)!ext!" (set /a cnt=!cnt!+1)
set /a cnt=!cnt!+1
echo move "%%a" "%dest%\!fname!(!cnt!)!ext!"
) else echo move "%%a" "%dest%\%%b"
Also note, this will recursively move all files from within the directory tree, if you only want to go into the first directory, simply remove /S from the for loop which will then simply become dir /B /A-D "%source%*.pdf"
Edit
As for your for /L loop (mentioned in comment)
Rather have a label and permanently goto it after completed. Here is a simple example of something like that, copy it to a script and run it, see the result:
#echo off
:label
echo Hi, this will run every 6 seconds and print this line. (infinitely).
timeout 6>nul
goto :label
So technically you can do the exact same for your loop, for instance:
#echo off
:label
setlocal enabledelayedexpansion
set "source=C:\Users\smorheng\Desktop\1\"
set "dest=D:\destination\folder"
set /a cnt=0
for /f "tokens=*" %%a in ('dir /S /B /A-D "%source%*.pdf"') do for /f "tokens=*" %%b in ('dir /B "%%a"') do if exist "%dest%\%%b" (
set "ext=%%~xa"
set "fname=%%~na"
if exist "%dest%\!fname!(!cnt!)!ext!" (set /a cnt=!cnt!+1)
set /a cnt=!cnt!+1
echo move "%%a" "%dest%\!fname!(!cnt!)!ext!"
) else echo move "%%a" "%dest%\%%b"
endlocal
timeout 6>nul
goto :label
Try replacing "RENAME" to SET newname see if that helps?
EDIT or try a vbs script instead of a batch?
`Set objFS = CreateObject("Scripting.FileSystemObject")
strFolder="c:\test"
Set objFolder = objFS.GetFolder(strFolder)
For Each strFile In objFolder.Files
If objFS.GetExtensionName(strFile) = "jpg" Then
strFileName = strFile.Name
If InStr(strFileName,"XXXXXXX") > 0 Then
strNewFileName = Replace(strFileName,"XXXXX","YYYYY")
strFile.Name = strNewFileName
End If
End If
Next `
So, basically I want a Batch file to read a .txt. The problem is that the Batch file needs to update everytime a new line gets written to the .txt
#echo off
set "pc=%1"
FOR /F "delims=:" %%A IN ('findstr /N .* "%pc%"') DO set "zeilen=%%A"
type %pc%
set /A zeilen1=%zeilen%
:loop
if not %zeilen% == %zeilen1% (
set "line="
set zeilen2=%zeilen% - 1
for /f %%a in ('more/e +%zeilen2% ^< %pc%') do (
if not defined line set "line=%%a"
)
echo %line%
set /A zeilen+=1
)
FOR /F "delims=:" %%A IN ('findstr /N .* "%pc%"') DO set "zeilen1=%%A
goto loop
I also can't use the type command (line 9-13) because I don't want to refresh the whole .txt only the last line.
sry for my poor english
Thanks
To start the Batch you need to do something like this call batch.cmd txtname.txt
A basic tail command can be written like so. Credit to #dbenham for his initial solution on DosTips.com
#echo off
call :Loop <"tailme.txt"
exit
:Loop
set "line="
set /p "line="
if defined line (
echo %line%
) else (
pathping -q 1 -p 300 localhost >nul
)
goto :loop
If you don't wish to use third party options and wish to keep it pure batch, it is very possible. From your question, it sounds like you wish to read the last line of a text file and have it update that text each time the text file is edited. Further more, this batch file much be call'ed to when it needs to be used.
To do this, we can compare the date it was last modified using forfiles in an for loop. The reason for this is that if we use the file properties EX: ECHO Last-Modified Date : %%~ta we will not get the properties down to seconds. Thus the file will only compare down to the minutes.
Now that we can grab the last modified properties we can use an IF statement to look for when the file get a new time stamp. From there we can use a modified script that reads only the last line of a text file (Configurable by set /a LINES=LINES+1 LINES+1 - Infin) made by #Patrick Cuff
To call this batch file you will want to use call ReadFile.bat txtname.txt
Call - Command
ReadFile.bat - Name of batch script
txtname.txt - Name of textfile to read
Bellow is the full script.
ReadFile.bat
#ECHO OFF
#GOTO READ
:LOOP
Rem | Look for changes
FOR /f %%a in ('forfiles /M %1 /C "cmd /c echo #fdate-#ftime"') DO (set FileTimeCurrent=%%a)
IF "%FileTimeLoad%"=="%FileTimeCurrent%" (goto LOOP) else (goto READ)
:READ
cls
Rem | Get current date
FOR /f %%a in ('forfiles /M %1 /C "cmd /c echo #fdate-#ftime"') DO (set FileTimeLoad=%%a)
Rem | Get the number of lines in the file
set LINES=0
for /f "delims==" %%I in (%1) do (
set /a LINES=LINES+1
)
Rem | Print the last line
set /a LINES=LINES-1
more +%LINES% < %1
goto LOOP
For help on any of the commands do the following:
call /?
set /?
for /?
if /?
So on.
In the below batch file, I am trying to check a directory, which will only contain text files (no sub-directories), for new files added. The script below executes but always displays New file detected. Eventually I will add it to the startup menu so that the directory is checked upon login. There probably is a better way, but I am not too familiar with batchfiles. Thank you :).
Batch
#echo off
:START
cls
set /a Old = 0
set /a New = 0
echo Checking for new annotated files...
for /f "tokens=*" %%P IN ('dir "path/to/directory" /A /b') do (set /a Old += 1)
set Old
echo Checking for new files..
for /f "tokens=*" %%P IN ('dir "path/to/directory" /A /b') do (set /a New += 1)
set New
goto COMPARE
:COMPARE
if %New% gtr %Old% goto NEWF (
goto NEWF
)
else (
goto OLDF
)
:NEWF
echo New File Detected.
echo.
pause
:OLDF
echo Nothing New.
echo.
pause
Since you are looking to see if any new files where created in a directory, you can use xcopy to check for files before x date. Since you did not post a date or time on your post, I will assume it's current date.
You do not need to check for files younger then the date given as you don't need to compare them. All you need to do is check if the files returned as "New" are less then 1. This can be done with the following:
if %New% gtr 0 (goto NEWF) else (goto OLDF)
If you wish to search sub-directoies in the future, you can use the /S switch with xcopy /L /S /D:.
For the pause statement's you had, you would have ran into problem's if the script was to continue (As it had no where to go). To fix this you can simply exit the script using goto :eof. Use echo( instead of echo.
#ECHO OFF
set /a New = 0
:: Gather & edit the date for xcopy.
SET CurrentDate=%date%
SET CurrentDate=%CurrentDate:/=-%
SET CurrentDate=%CurrentDate:* =%
:: Check for files created today.
for /f "delims=" %%i in ('xcopy "path/to/directory" /L /I /D:%CurrentDate%') do (set /a New+=1)
set /a New-=1
goto COMPARE
:COMPARE
if %New% gtr 0 (goto NEWF) else (goto OLDF)
:NEWF
echo New File Detected.
echo(
pause
goto :eof
:OLDF
echo Nothing New.
echo(
pause
goto :eof
store the value in a file old.txt. If this file exist get the value inside and loop true all .txt files and test the value. Here the comented code :
#echo off&cls
setlocal enabledelayedexpansion
:: Default value
set "New=0"
set "old=0"
:: If exist old.txt get the real value
if exist old.txt set /p Old=<old.txt
echo Checking for new annotated files...
::Count of the txt files
for /f %%$ IN ('dir *.txt') do set /a New+=1
:: Update the value of the old.txt for the next check
echo !New!>old.txt
:: Testing the 2 values
if !New! gtr %Old% (goto NEWF) else (goto OLDF)
:NEWF
echo New File Detected.
echo.
pause
exit/b
:OLDF
echo Nothing New.
echo.
pause
exit/b
I have an SSIS job running in a batch file that executes asynchronously.
I need to know when the SSIS job is done outputting a bunch of PDF and XLS files.
The files appear in two directories, PDFs first XLS following.
I chose to write a second batch file that will wait a bit after the SSIS job exits, then check to see that the last file written in the directory has been there for 3 minutes, which, after observation, is an ample interval for the job to write a file.
The problem is: the outer loop is never run if the inner loop iterates more than once, which seems to indicate that the second time MYPATH is declared, the value of n is foobarred, but this cannot be true because the script is returning 1, rather than crapping out when Arr[badval] is checked.
#ECHO OFF
REM SSIS process is asyncronous, and executes in background. Problematic for
REM DAG, which relies on exit code to understand process.
REM Check for "last file written" in output directories every N seconds.
REM It's a good bet we are done when they match.
#setlocal enabledelayedexpansion
REM "sleep" wait for non-existent command to complete
waitfor ragnarok /t 180>NUL 2>&1
set Arr[0]=E:\pdf_output
set Arr[1]=E:\xls_output
for /l %%n in (0,1,2) do (
if defined Arr[%%n] (
REM set value for path within loop or scope will bite you
set MYPATH=!Arr[%%n]!
echo Checking file ages in !MYPATH!.
) else (
echo Done
EXIT /B 0
)
:while1
REM don't put a blank line here, it throws a syntax error
FOR /F "delims=|" %%I IN ('DIR !MYPATH! /B /O:D') DO SET FILE1=%%I
REM "sleep" use ping for delay, since waitfor will break loop
arp -s 192.168.1.254 >nul
ipconfig /flushdns >nul
ping localhost -n 180 >nul
FOR /F "delims=|" %%I IN ('DIR !MYPATH! /B /O:D') DO SET FILE2=%%I
if NOT "!FILE1!" == "!FILE2!" (
goto :while1
)
)
endlocal
REM Something is wrong, return 1 to stop DAG and invite inspection.
exit /B 1
Breaking the while loop into a subroutine as #aschipfl suggested seems to have done the trick:
#ECHO OFF
REM SSIS process is asyncronous, and executes in background. Problematic for
REM DAG, which relies on exit code to understand process.
REM Check for "last file written" in output directories every N seconds.
REM It's a good bet we are done when they match.
#setlocal enabledelayedexpansion
REM "sleep" wait for non-existent command to complete
waitfor ragnarok /t 120>NUL 2>&1
set Arr[0]=E:\pdf_output
set Arr[1]=E:\xls_output
for /l %%n in (0,1,2) do (
if defined Arr[%%n] (
REM set value for path within loop or scope will bite you
set MYPATH=!Arr[%%n]!
echo Checking file ages in !MYPATH!.
CALL :checkfiles
) else (
echo Done
goto :NormalExit
)
)
:checkfiles
:while1
REM don't put a blank line here, it throws a syntax error
FOR /F "delims=|" %%I IN ('DIR !MYPATH! /B /O:D') DO SET FILE1=%%I
REM "sleep" use ping for delay, since waitfor will break loop
arp -s 192.168.1.254 >nul
ipconfig /flushdns >nul
ping localhost -n 120 >nul
FOR /F "delims=|" %%I IN ('DIR !MYPATH! /B /O:D') DO SET FILE2=%%I
if NOT "!FILE1!" == "!FILE2!" (
goto :while1
)
endlocal
:NormalExit
exit /B 0
REM Something is wrong, return 1 to stop DAG and invite inspection.
exit /B 1
New to batch scripting. Trying to write a script which checks for files with filename starting with LEND by polling a directory and if the file is not received by 17:30, then write a log message to log file. I have written the below batch script, the script runs fine as long as there are no files in the directory. As soon as I put files in there, it stops running. And restarts if I delete the files from that directory. Could you please advise where I am going wrong?
Thanks
#echo off
set I=0
set log=C:\logs\alerting.log
:recurse
for /f %%P in ('dir /b "C:\incoming\LEND*"') do (call :countfiles)
set Time=%time:~0,5%
echo Filecount: %I% at Time: %Time% >> %log%
if %Time%==17:30 goto OUT
pause 60
goto :recurse
:countfiles
set /a I+=1
:OUT
if %I%==0 echo LEND Files not received >> %log%
EXIT
Your code goes from countfiles to exit. Try this:
:countfiles
set /a I+=1
goto:eof
There were actually several flaws - reusing the time variable, expecting pause to be used as a delay, the time frame could have been missed in the test, and other more minor things.
This is tested as far as the file counting goes but not the 17:30 branch
I changed the style of a few commands and variable names (I is too much like l and i and 1 in many fonts)
#echo off
set log=C:\logs\alerting.log
:loop
for /f %%P in ('dir /b "C:\incoming\LEND*" 2^>nul ^| find /c /v "" ') do set c=%%P
set now=%time:~0,5%
echo Filecount: %c% at Time: %now%
echo Filecount: %c% at Time: %now% >> %log%
if %now:~0,2%%now:~3,2% GTR 1730 goto :OUT
ping -n 60 localhost >nul
goto :loop
:OUT
if %c% EQU 0 echo LEND Files not received >> %log%
EXIT