Ok I have found a few questions on this, but each are saying make sure the use CALL and exit \b or goto eof in the 2nd bat file but for some reason I am not getting this to work, I have tried both, the batch file exits every time after executing the first call statement:
batch file 1 (myscript.bat):
:#echo off
del files
dir /B /O-D | find "test2" > tmp
dir /B /O-D | find "test3" > tmp2
CALL head 1 tmp > files
CALL head 1 tmp2 >> files
head.bat:
#echo off
if [%1] == [] goto usage
if [%2] == [] goto usage
call :print_head %1 %2
goto :eof
REM
REM print_head
REM Prints the first non-blank %1 lines in the file %2.
REM
:print_head
setlocal EnableDelayedExpansion
set /a counter=0
for /f ^"usebackq^ eol^=^
^ delims^=^" %%a in (%2) do (
if "!counter!"=="%1" goto :eof
echo %%a
set /a counter+=1
)
goto :eof
:usage
echo Usage: head.bat COUNT FILENAME
Execution:
C:\Users\ots>myscript.bat
C:\Users\ots>del files
C:\Users\ots>dir /B /O-D | find "test2" 1>tmp
C:\Users\ots>dir /B /O-D | find "test3" 1>tmp2
C:\Users\ots>CALL head 1 tmp 1>files
C:\Users\ots>
How can I get it to run the second "tmp2" Call line?
Thanks!
Your code is fine, both calls are indeed made.
The issue is that you are setting echo to OFF in head.bat, so after the first call, your command does not get echoed on the console, but that does not mean the file is not called.
To verify this, remove the #echo off from head.bat, and you will see your second CALL command.
Related
I know batch isn't the best vehicle for this but my requirements dictate that I keep it.
I have text that looks like the following (it also has blank lines):
Line AAA text
Line BBB text
! ***### START
Body text here
! ***### END
Line XXX
Line YYY
!Comment Line etc
I want to remove the ! ***### START and END lines and everything in between and then save over the original file.
I found and modified the code below but it strips out my blank lines and the ! characters.
#echo off
setlocal enabledelayedexpansion
set "sourceFile=c:\temp\startfile.txt"
set "tempFile=c:\temp\tempfile.txt"
set "StartPhrase=! ***### START"
set "EndPhrase=! ***### END"
set /a lineNum=0
REM check file for search phrase, store line as refLine
FOR /F "delims=" %%i IN (%sourceFile%) DO (
set /a lineNum+=1
echo !lineNum! = "%%i"
if "%%i" == "%StartPhrase%" (
echo Found "%StartPhrase%" on line !lineNum!
set /a StartrefLine=!lineNum!
)
if "%%i" == "%EndPhrase%" (
echo Found "%EndPhrase%" on line !lineNum!
set /a EndrefLine=!lineNum!
)
)
REM make backup
copy "%sourceFile%" "%sourceFile%-%DATE:/=-% %TIME::=-%.txt"
echo. 2>%tempFile%
REM Rewrite file
set /a lineNum=0
set /a lowEnd=%StartrefLine%
echo "Set low end to %lowEnd%"
set /a highEnd=%EndrefLine%
echo "Set high end to %highEnd%"
FOR /F "delims=" %%i IN (%sourceFile%) DO (
set /a lineNum+=1
if !lineNum! GTR %lowEnd% (
if !lineNum! LSS %highEnd% (
echo "Skipping line #!lineNum!"
)
)
if !lineNum! LSS %lowEnd% (
echo "Writing Line !lineNum! %%i to temp file..."
echo %%i >> %tempFile%
)
if !lineNum! GTR %highEnd% (
echo "Writing Line !lineNum! %%i to temp file..."
echo %%i >> %tempFile%
)
)
REM get target filename only
for %%F in ("%sourceFile%") do set fname=%%~nxF
REM del original file and rename tempfile
echo "Deleting original file..."
echo Y | del "%sourceFile%"
echo "Renaming %tempFile% to %fname%"
ren "%tempFile%" "%fname%"
A possible and quite simple way is to let the particular line markers toggle a flag that indicates whether or not the currently iterated line is to be output:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=C:\TEMP\startfile.txt"
set "_TMPF=%TEMP%\%~n0_%RANDOM%.tmp"
set "_START=! ***### START"
set "_END=! ***### END"
rem // Initialise flag:
set "FLAG=#"
rem // Write to temporary file:
> "%_TMPF%" (
rem /* Loop through lines of input file; `findstr` precedes each line with
rem line number plus `:`, so they do not appear empty to `for /F`: */
for /F "delims=" %%L in ('findstr /N "^" "%_FILE%"') do (
rem // Store current line string (with line number prefix) to variable:
set "LINE=%%L"
rem // Toggle delayed expansion to avoid loss of `!`:
setlocal EnableDelayedExpansion
rem // Remove line number prefix to retrieve original line string:
set "LINE=!LINE:*:=!"
rem // Check contents of current line:
if "!LINE!"=="!_START!" (
endlocal & set "FLAG="
) else if "!LINE!"=="!_END!" (
endlocal & set "FLAG=#"
) else (
rem // Check state of flag for outputting:
if defined FLAG echo(!LINE!
endlocal
)
)
) && (
rem // Move temporary file onto target file:
move /Y "%_TMPF%" "%_FILE%"
)
endlocal
exit /B
This task could be done with worst script interpreter available for this task with following code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFile=C:\Temp\startfile.txt"
if not exist "%SourceFile%" goto :EOF
set "TempFile=%SourceFile%.tmp"
set "PrintLines=1"
(for /F "delims=" %%I in ('%SystemRoot%\System32\findstr.exe /N /R "^" "%SourceFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
if defined PrintLines (
if not "!Line: ***### START=!" == "!Line!" (
endlocal
set "PrintLines="
) else (
echo(!Line:*:=!
endlocal
)
) else (
if not "!Line: ***### END=!" == "!Line!" (
endlocal
set "PrintLines=1"
) else endlocal
)
))>"%TempFile%"
move /Y "%TempFile%" "%SourceFile%"
if exist "%TempFile%" del "%TempFile%"
endlocal
for /F results in ignoring all empty lines. For that reason command findstr is used to output all lines with line number and colon at beginning in a separate command process started with %ComSpec% /c in background. So there is no empty line anymore in captured output of findstr.
Each captured line starting with a digit in range 1 to 9 is assigned completely to the loop variable I because of using option delims= to define an empty list of string delimiters to disable the default line splitting behavior on normal spaces and horizontal tabs.
The line with line number and colon at beginning is assigned to the environment variable Line while delayed environment variable expansion is disabled. This is important as otherwise the Windows command processor cmd.exe processing the batch file would parse the command line set "Line=%%I" after having replaced %%I by current line with enabled delayed expansion and would interpret each ! as beginning/end of a delayed expanded environment variable.
Then the delayed expansion is enabled for further processing the line depending on printing lines currently enabled as by default until a line is found containing the string ***### START. Next the environment variable PrintLines is undefined until a line is found containing the string ***### END on which PrintLines is defined again for the following lines.
Please read second half of this answer for details about the commands SETLOCAL and ENDLOCAL.
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.
del /?
echo /?
endlocal /?
findstr /?
for /?
if /?
move /?
set /?
setlocal /?
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q65218525.txt"
SET "outfile=%destdir%\outfile.txt"
SET "blockstart=! ***### START"
SET "blockend=! ***### END"
SET "repro=Y"
(
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r ".*" "%filename1%"') DO (
IF /i "%%b"=="%blockstart%" SET "repro="
IF /i "%%b"=="%blockend%" (SET "repro=Y") ELSE (IF DEFINED repro IF "%%b"=="" (ECHO.) ELSE (ECHO %%b))
)
)>"%outfile%"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q65218525.txt containing your data for my testing.
Produces the file defined as %outfile%
Since your code saves the original file under a new name and creates a new file with the old name but your requirement seems to be to simply overwrite the old file, I'll leave that part as an exercise.
First, define the strings involved, and a flag (which I've called repro) which is initialised to reproduce the data.
Then use findstr with the /N option to prefix each line, including blank lines, with number: which is then parsed by the for/r to put the number in %%a and the text in %%b.
Check %%b for the target strings and frob the repro flag as appropriate to select whether to reproduce the line read or not.
Another way to do this would be using PowerShell. Invoke it from the command line or a .bat file script using:
powershell -NoLogo -NoProfile -File '.\Slice-File.ps1'
=== Slice-File.ps1
$SourceFile = 'C:\src\t\Slice-File.txt'
$TempFile = New-TemporaryFile
$WriteIt = $true
Get-Content -Path '.\Slice-File.txt' |
ForEach-Object {
if ($_ -eq '! ***### START') { $WriteIt = $false }
if ($WriteIt) { $_ }
if ($_ -eq '! ***### END') { $WriteIt = $true }
} |
Out-File -FilePath $TempFile -Encoding ascii
Remove-Item -Path $SourceFile
Move-Item -Path $TempFile -Destination $SourceFile
#echo off
call :checkFTP1 %* > all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
call :checkFTP2 %* >> all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
call :checkFTP3 %* >> all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
call :doCommands1 %* >> all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
call :doCommands2 %* >> all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
call :doCommands3 %* >> all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
call :doCommands4 %* >> all_log_all_log_%date:~10,4%%date:~4,2%%date:~7,2%.log 2>&1
exit /b
:checkFTP1
#echo off
Setlocal
:: Is folder empty
set _TMP=
for /f "delims=" %%a in ('dir /b "C:\test\folder1"') do set _TMP="%%a"
IF {%_TMP%}=={} (
goto :Exit1
) ELSE (
goto :checkFTP2
)
Endlocal
:checkFTP2
#echo off
Setlocal
:: Is folder empty
set _TMP=
for /f "delims=" %%a in ('dir /b "C:\test\folder2"') do set _TMP="%%a"
IF {%_TMP%}=={} (
goto :Exit2
) ELSE (
goto :checkFTP3
)
Endlocal
:checkFTP3
#echo off
Setlocal
:: Is folder empty
set _TMP=
for /f "delims=" %%a in ('dir /b "C:\test\folder3"') do set _TMP="%%a"
IF {%_TMP%}=={} (
goto :Exit3
) ELSE (
goto :doCommands1
)
Endlocal
:doCommands1
call script1.bat
if %errorlevel% EQU 0 (goto :doCommands2 ) Else ( ECHO error on script 1 ,2,3,4)
exit
:doCommands2
call script2.bat
if %errorlevel% EQU 0 (goto :doCommands3 ) Else ( ECHO Script 1 Completed Successfully , ERRORS on 2,3,4)
exit
:doCommands3
call script3.bat
if %errorlevel% EQU 0 (goto :doCommands4) Else ( ECHO Script 2 Completed Successfully , ERRORS on 3,4)
exit
:doCommands4
call script4.bat
if %errorlevel% EQU 0 (goto :completed1) Else ( ECHO Script 3 Completed Successfully , ERRORS on 4)
exit
:Exit1
Echo Today Date %DATE% at %Time%
Echo ###################FTP-1 FILES MISSING #########################
Exit
:Exit2
Echo Today Date %DATE% at %Time%
Echo ###################FTP-2 FILES MISSING (#########################
Exit
:Exit3
Echo Today Date %DATE% at %Time%
Echo ###################FTP-3 FILES MISSING #########################
Exit
:completed1
Echo Today Date %DATE% at %Time%
Echo ###################all scripts Completed Successfully#########################
Exit
I have above batch file which calls multiple bat files. I have tested the script and it worked fine.
My only issue is that the log file generated contains all information, and it's a large file.
Is it possible to just log comments and echo, and exclude what executed in screen?
For example I don't want 1 file moved to be showing in log file.
I've taken your code and re-written it to use generic functions which deduplicates the code into an a more easily managed form and allows you to add or remove any steps to FTP and Script sections as needed by editing the list of variables.
I also only return output that does not include the "file(s) moved".
Alternatively if you really only want the status lines to print you could change this to just have those print to the log and not have all info print to the log (this is being done because you are putting the redirection to the log on the calls to other steps.
Also the way this was written before it was actually going through all the goto commands and not needing the calls to each at the top.
Here is the refactored code, I haven't tested it but it should be fine I have to step out for a few hours and you can ask any questions and I'll be happy to answer when I have time.
#( Setlocal EnableDelayedExpansion
echo off
SET "_FolderList="C:\test\folder1" "C:\test\folder1" "C:\test\folder1" "
SET "_ScriptList="c:\test\script1.bat" "E:\script2.bat" "C:\Path\To\script3.bat" "C:\Path\To\script4.bat" "
SET "_Scripts_Failed=1,2,3,4"
SET "_Scripts_Completed="
SET "_Continue=0"
CALL :GetDateTime
SET "MasterLog=all_log_all_log_!IsoDate!_!IsoTime!.log"
)
CALL :Main
( Endlocal
EXIT /B
)
:Main
SET /A "_Counter=0"
FOR %%_ IN (%_FolderList%) DO (
IF DEFINED _Continue (
SET /A "_Counter+=1"
CALL :CheckFTP_List %%~_
)
)>> "%MasterLog%"
SET /A "_Counter=0"
FOR %%_ IN (%_FolderList%) DO (
IF DEFINED _Continue (
SET /A "_Counter+=1"
CALL :DoCommands_List %%~_
)
)>> "%MasterLog%"
IF DEFINED _Continue (
Echo Today Date %DATE% at %Time%
Echo ###################all scripts Completed Successfully#########################
)
GOTO :EOF
:CheckFTP_List
REM Is folder empty
for /f "delims=" %%a in ('dir /b /A-D "%*') do (
set "_Continue=%%a" )
IF NOT Defined _Continue (
Echo.Today Date on %DATE% at %Time%
Echo.###################FTP-%_Counter% FILES MISSING #########################
)
GOTO :EOF
:DoCommands_List
call "*%" | FIND /I /V "file(s) moved" &REM only outputs lines that don't contain files moved.
if %errorlevel% NEQ 0 (
SET "_Continue="
SET "_Scripts_Completed=%_Scripts_Completed:,1=1%"
SET "_Scripts_Failed=!_Scripts_Failed:%_Scripts_Completed%=!"
Echo Today Date %DATE% at %Time%
ECHO. Error encountered on Script %Counter%! -- Completed Scripts: !_Scripts_Completed! -- Failed Scripts: !_Scripts_Failed!
) ELSE (
SET "_Scripts_Completed=%_Scripts_Completed:,1=1%,%Counter%"
)
GOTO :EOF
:GetDateTime
FOR /F "Tokens=1-7 delims=MTWFSmtwfsouehrandit:-\/. " %%A IN ("%DATE% %TIME: =0%") DO (
FOR /F "Tokens=2-4 Delims=(-)" %%a IN ('ECHO.^| DATE') DO (
SET "%%~a=%%~A"
SET "%%~b=%%~B"
SET "%%~c=%%~C"
SET "HH=%%~D"
SET "Mn=%%~E"
SET "SS=%%~F"
SET "Ms=%%~G"
)
)
SET "IsoTime=%HH%.%Mn%.%SS%.%Ms%"
SET "IsoDate=%yy%-%mm%-%dd%"
GOTO :EOF
I want to know error line number where error was occure by batch script and also i want to print whole line in batch script?
set t=%date%_%time%
set x=FORD_DLCM_T6_FTC
set a="%m%\%x%"
cd /d "C:\PRQA\PRQA-Framework-2.1.2\common\bin"
qacli admin --set-license-server 5055#00.00.0.0 || goto :error
qacli admin --debug-level DEBUG || goto :error
goto :EOF
:error
set remark= %ERRORLEVEL%
set status= Failure
echo ProjectName: %x%
echo Status: %status%
echo Remark: %remark%
echo Date: %t%
echo %x%,%status%,traceback(),%t% > "C:\Test\Build.csv"
echo Failed with error #%errorlevel%.
exit /b %errorlevel%
can any one help me out?
jeb has described how the search for the right line works. in the event of an error, a call is triggered and the parameters are a unique string and an offset, which points to the number of missing lines to the correct line. Findstr looks for the unmistakable string and prints that line number. With the settlement that's right again.
I've put together some macros to show that there are other ways to read the right line.
#echo off
setlocal
set prompt=$g$s
call :setAllmacros
(call)
rem begin in echo off - what line is it please ?
%ID-1:##==rem?%
(call )
%ID-1:##==call%
set/a+
%ID-1:##==001% call :ErrorLogging Line:%%L Errorlevel:%errorlevel%
echo 2
(call) || %ID-0:##==2% call :Errorlogging Line:%%L Errorlevel:%%errorlevel%%
echo %errorlevel%
find /n || %ID-0:##==003% call :Errorlogging Line:%%L Errorlevel:%%errorlevel%%
%ID-0:##==008%
pushG 556
%ID-1:##==004% call :ErrorLogging Line:%%L Errorlevel:%errorlevel%
%Line#print%:33=="
pause
exit /b
:errorlogging
#echo on
rem %*
#echo off
exit /b
:setAllmacros
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
(set ^"lf=^
%== define LF + CR ==%
)
for /f %%i in ('copy /z "%~f0" nul') do set "CR=%%i"
rem Prints the fullline itself with LineNumber into stderr
rem usage: %Line#print%:UniqueID"
rem command || %Line#print%:01"
set "Line#print= # <"%~f0" >&2 find /n "%%Line#print%%"
rem Read the fullline BEFORE into Variables with LineNumber; do something ...
rem usage: command 1 line before
rem %ID-1:##==01% [command %%L ... %%M ...]
set ID-1= if errorlevel 1 for /f "usebackQtokens=1*delims=:" %%L in (^
`cmd /v /c ^"findstr /n /r /c:"..*^!CR^!*^!LF^!.*ID-1:.#^=^##%%" "%~f0"^"`) do ^>^&2 echo BatchLine: %%L -- %%M ^&
rem Read the fullline itself into Variables with LineNumber; do something ...
rem usage: command || %ID-0:##==01% [command %%L ... %%M ...]
set ID-0= # for /f "tokens=1*delims=:" %%L in ('findstr /n /r /c:"ID-0:.#=##%%" "%~f0"') do ^>^&2 echo BatchLine: %%L -- %%M ^&
exit /b
hope it helps
Phil
I have about 12TB (and growing) library, distributed over 3 HDDs, of video files and I would like to back them up to an external harddrive. I am using Windows 10 Pro.
My backup drive has only 8TB and I would like to always backup the newest 8TB of video files. So far I have tried about 10 sync tools but none of them allowed me to copy files according to creation date.
Also with robocopy I haven't found a way to copy only the latest 8TB of files.
Any suggestions?
I have 2 batch scripts for you that do what you have asked for. The main difference between them is, that the 1st script is using where to locate all the files which will use the timestamp of the last change. To use another timestamp e.g. last access or time of creation you have to use the 2nd script I attached which uses dir.
1.
Batch script using where to locate files:
It takes minimum 2 arguments:
Usage: batch.bat <dst> <src_1> [<src_...> <src_n>]
It uses the where /r <src_n> * /t command which will build a list of all files in all subdirectories with a timestamp of the last change in the following format:
<size> <date> <time> <file name>
5397 11.07.2017 14:32:09 C:\Users\...\foo.txt
10860 12.07.2017 11:25:15 C:\Users\...\bar.log
The timestamp is of last change if you need the time of the creation or last access take the 2nd batch script below which is using dir as there is the possibility to choose between different timestamps.
This output will be written (without the column size) into a temporary file under the temp dir %TEMP% (will be deleted automatically after script) for every source that is passed via the argument list. The complete temporary file is sorted by the date and time, newest first.
This sorted output will be used to copy it into the destination folder.
Example:
Current directory in cmd is C:\...\Desktop):
batch.bat "backup_folder" "F:\folder" "F:\folder with space"
Current directory somewhere:
batch.bat "C:\...\Desktop\backup_folder" "F:\folder" "F:\folder with space"
The C:\...\Desktop\backup_folder will contain 2 folders folder and folder with space which contain all files of these source folders after the scripts operation.
In your case the batch script would copy only 8 TB of the newest files because then the drive will be full and the batch script will exit because it recognizes copy errors.
The batch script:
#echo off
setlocal enabledelayedexpansion
rem Check if at least 2 arguments are passed
set INVARGS=0
if [%1] == [] set INVARGS=1
if [%2] == [] set INVARGS=1
if %INVARGS% == 1 (
echo Usage: %0 ^<dst^> ^<src_1^> ^<src_...^> ^<src_n^>
goto :EOF
)
rem Store Carriage return character in CR (used for spinner function, see below)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
rem Set temp file name
set "uniqueFile=%TEMP%\%0_%RANDOM%.tmp"
rem Set destination path and shift to next argument
set "dstpath=%~1"
shift
rem Store src_1 to src_n arguments into src array
set idx=0
:again
rem If %1 is blank, we are finished
if not [%1] == [] (
if not exist "%~1" (
echo The following source folder doesn't exist:
echo "%~1"!
echo The program will terminate!
goto :end
)
pushd "%~1"
set "src[%idx%]=!cd!"
if [!src[%idx%]:~-1!] == [\] (
set src[%idx%]=!src[%idx%]:~0,-1!
)
set /a idx=%idx%+1
popd
rem Shift the arguments and examine %1 again
shift
goto :again
)
rem Build command string:
rem where /r "src_1" * /t ^& where /r "src_..." * /t ^& where /r "src_n" * /t ^& break"
set "command="
for /F "tokens=2 delims==" %%s in ('set src[') do (
set "command=!command!where /r "%%s" * /t ^& "
)
set "command=!command!break"
echo "Command: ^<!command!^>"
rem Clear temp file and write files to copy in it
break>"%uniqueFile%"
for /f "tokens=2,3,4,* delims= " %%F in ('!command!') do (
call :spinner
echo %%F %%G %%H %%I>>"%uniqueFile%"
)
rem Open the built file list
echo File list will be opened...
%uniqueFile%
rem Ask user if copying should start
echo Should this files copied into %dstpath%? (Y/N)
set INPUT=
set /P INPUT=Answer?:%=%
if not [%INPUT%] == [y] (
if not [%INPUT%] == [Y] (
goto :end
)
)
set "dstpathPart="
rem Sort files newest first (last changed timestamp)
for /f "tokens=3,* delims= " %%F in ('type "%uniqueFile%" ^| sort /r') do (
rem Build destination part from source folder names
call :buildDestinationPath dstpathPart "%%F %%G"
rem Prepend the destination folder
set "dstFile=!dstpath!\!dstpathPart!"
rem Make directories that doesn't exists
for %%F in ("!dstFile!") do set "directory=%%~dpF"
if not exist "!directory!" ( mkdir "!directory!" )
rem Copy files and echo it
echo copy /y "!file!" "!dstFile!"
copy /y "!file!" "!dstFile!"
echo.
rem If copying failed exit program
if errorlevel 1 (
echo Copying failed... Maybe there is no more space on the disk!
echo The program will terminate!
goto :end
)
)
goto :end
rem Function definitions
:buildDestinationPath
for /F "tokens=2 delims==" %%s in ('set src[') do (
rem Go into folder e.g.: C:\src_1\ --> C:\
pushd "%%s"
cd ..
rem file contains full path of the where command
set "file=%~2"
rem Remove trailing space
if "!file:~-1!" == " " (
call set "file=%%file:~0,-1%%"
)
rem remove src folder from file to make it relative
rem e.g. C:\src_1\foo\bar\file1.txt --> src_1\foo\bar\file1.txt
call set "dstpathPart_temp=%%file:!cd!=%%"
rem Switch back to origin folder
popd
rem If the folder name changed the substring taken was right so take next
if not [!dstpathPart_temp!] == [!file!] (
set "%~1=!dstpathPart_temp!"
goto :next
)
)
:next
goto :EOF
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Building file list... !spinChars:~%spinner%,1!!CR!"
goto :EOF
:end
del "%uniqueFile%"
goto :EOF
2.
Batch script using dir to locate files:
It takes one more argument so that you need minimum 3 arguments:
Usage: batch.bat <timeordering> <dst> <src_1> [<src_...> <src_n>]
It will generate the same list as explained above but with the help of the dir command. The dir command takes the following parameter which is the <timeordering> parameter of the script:
/tc Creation
/ta Last access
/tw Last written
The batch script:
#echo off
setlocal enabledelayedexpansion
rem Check if at least 2 arguments are passed
set INVARGS=0
if [%1] == [] set INVARGS=1
if [%2] == [] set INVARGS=1
if [%3] == [] set INVARGS=1
if %INVARGS% == 1 (
echo Usage: %0 ^<timeordering^> ^<dst^> ^<src_1^> ^<src_...^> ^<src_n^>
goto :EOF
)
rem Store Carriage return character in CR (used for spinner function, see below)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
rem Set temp file name
set "uniqueFile=%TEMP%\%0_%RANDOM%.tmp"
rem Set timeordering and destination path and shift to next argument
set "timeordering=%~1"
shift
set "dstpath=%~1"
shift
rem Store src_1 to src_n arguments into src array
set idx=0
:again
rem If %1 is blank, we are finished
if not [%1] == [] (
if not exist "%~1" (
echo The following source folder doesn't exist:
echo "%~1"!
echo The program will terminate!
goto :end
)
pushd "%~1"
set "src[%idx%]=!cd!"
if [!src[%idx%]:~-1!] == [\] (
set src[%idx%]=!src[%idx%]:~0,-1!
)
set /a idx=%idx%+1
popd
rem Shift the arguments and examine %1 again
shift
goto :again
)
rem Clear temp file and write files to copy in it
break>"%uniqueFile%"
rem call commands with all sources:
rem call :getFileInformation /TC "src_1\*"
rem /TW
rem /TA
for /F "tokens=2 delims==" %%s in ('set src[') do (
call :getFileInformation %timeordering% "%%s\*" "%uniqueFile%""
)
rem Open the built file list
echo Unsorted file list will be opened...
%uniqueFile%
rem Ask user if copying should start
echo Should this files copied into %dstpath%? (Y/N)
set INPUT=
set /P INPUT=Answer?:%=%
if not [%INPUT%] == [y] (
if not [%INPUT%] == [Y] (
goto :end
)
)
set "dstpathPart="
rem Sort files newest first (last changed timestamp)
for /f "tokens=3,* delims= " %%F in ('type "%uniqueFile%" ^| sort /r') do (
rem Build destination part from source folder names
call :buildDestinationPath dstpathPart "%%F %%G"
rem Prepend the destination folder
set "dstFile=!dstpath!\!dstpathPart!"
rem Make directories that doesn't exists
for %%F in ("!dstFile!") do set "directory=%%~dpF"
if not exist "!directory!" ( mkdir "!directory!" )
rem Copy files and echo it
echo copy /y "!file!" "!dstFile!"
copy /y "!file!" "!dstFile!"
echo.
rem If copying failed exit program
if errorlevel 1 (
echo Copying failed... Maybe there is no more space on the disk!
echo The program will terminate!
goto :end
)
)
goto :end
rem Function definitions
:buildDestinationPath
for /F "tokens=2 delims==" %%s in ('set src[') do (
rem Go into folder e.g.: C:\src_1\ --> C:\
pushd "%%s"
cd ..
rem file contains full path of the where command
set "file=%~2"
rem Remove trailing space
if "!file:~-1!" == " " (
call set "file=%%file:~0,-1%%"
)
rem remove src folder from file to make it relative
rem e.g. C:\src_1\foo\bar\file1.txt --> src_1\foo\bar\file1.txt
call set "dstpathPart_temp=%%file:!cd!=%%"
rem Switch back to origin folder
popd
rem If the folder name changed the substring taken was right so take next
if not [!dstpathPart_temp!] == [!file!] (
set "%~1=!dstpathPart_temp!"
goto :next
)
)
:next
goto :EOF
:getFileInformation
for /f "delims=" %%a in ('dir /s /b /a-d %~1 "%~2"') do (
for /f "tokens=1,2 delims= " %%b in ('dir %~1 "%%a" ^| findstr /l /c:"%%~nxa"') do (
echo %%b %%c %%a>>"%~3"
call :spinner
)
)
goto :EOF
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Building file list... !spinChars:~%spinner%,1!!CR!"
goto :EOF
:end
del "%uniqueFile%"
goto :EOF
Hi I am having problems with one of my first CMD scripts, any suggestions on how to go about this loop with grabbing the results outputted the command window with the if statements?
#echo off
:BEGIN
T:
cd js
cd ddf
cd invent
for %%s in ("invstk" "labmas") do (
Call Isutl -r %%s
if result contains "%ISUTL=20: Cannot open index file" goto SendEmail else if the result = "Indexing Complete" continue to next file in
list, if result not contains "%ISUTL=20: Cannot open index file" or "Indexing Complete" then call Isutl -r on that file again
)
:SendEmail
:DONESCAN
Exit
See if this does what you need:
#echo off
:BEGIN
cd /d "t:\js\ddf\invent"
for %%s in ("invstk" "labmas") do call :routine "%%s"
del file.log 2>nul
pause
goto :EOF
:routine
Call Isutl -r "%~1" >file.log 2>&1
find /i "ISUTL=20: Cannot open index file" <file.log >nul && goto SendEmail
find /i "Indexing Complete" <file.log >nul && goto :EOF
goto :routine
:SendEmail
rem send email
goto :EOF