batch - File last modification time with seconds - batch-file

I want to know when a file has been modified for the last time.
I can get these infos using the following batch script:
FOR %%i IN (myfile) DO SET modif_time=%%~ti
The problem is that I need the second of the last modification and the command %~t returns the date and the time with only hours and minutes.
I can only check the seconds by manually viewing the "property window" file by file.
How can I get the time with seconds in batch?

In Windows 7 and forward (or via Resource Kit for XP) you can use forfiles for this. Something like:
forfiles /m *.* /c "cmd /c ECHO The last modified date of: #file is: #ftime"
In a directory with the following files:
myTest.txt
myTest2.txt
I get:
The last modified date of: "myTest.txt" is: 13:21:07
The last modified date of: "myTest2.txt" is: 13:21:20

wmic datafile where name="FileName" get LastModified
FileName must contain the full path with double backspaces.
Sorting example (recent first):
for /f "delims=" %a in ('wmic datafile where "drive='c:' and path='\\windows\\'" get LastModified^,Name /format:table^|find ":"^|sort /r') do #echo %a

wmic datafile where "drive='c:' and path='\\windows\\'" get "Last Modified",Name

You can embed a small JScript in the batch file to get the last modified epoch:
#if (#a==#b) #end /*
#echo off
SetLocal EnableDelayedExpansion
set EPOCH=0
FOR /F "delims=" %%D in ('cscript /nologo /e:jscript "%~f0" "%1"') do (
set EPOCH=%%D
)
echo Last modified (epoch-seconds): !EPOCH!
goto :eof
*/
var fs = new ActiveXObject("Scripting.FileSystemObject");
var filename = WSH.Arguments(0)
var millis = -1
if (fs.FileExists(filename))
{
var file = fs.GetFile(filename);
millis = Date.parse(file.DateLastModified) / 1000;
}
WSH.Echo(millis);
The /* */ will comment out the batch script while running as a JScript, and the #if (#a==#b) #end and goto :eof will skip the JScript while running as a batch script
>epoch.bat epoch.bat
Last modified (epoch-seconds): 1533282229
>epoch.bat "epoch.bat"
Last modified (epoch-seconds): 1533282229
>epoch.bat notareal.file
Last modified (epoch-seconds): -1

Related

How to compress all files with exception of newest file in each subfolder of a folder into one ZIP file per subfolder?

I'm trying to create a batch script that will zip all the contents in each subdirectory except the latest (or latest few). I'm currently attempting in Windows with 7-Zip but the directory is technically on a Linux server so any suggestions geared towards a Linux command is welcome.
The directory structure is like this:
Directory-Parent
---Sub-Directory-1
--------File1
--------File2
--------File3
---Sub-Directory-2
--------File1
--------File2
I would like to run a batch at the Directory-Parent level that will create a zip in each sub-directory of all the files except the latest 1 (or few if possible). I also want to add the year to the end of the zip file name.
So the result would be:
Directory-Parent
-Sub-Directory-1
--------File1
--------Sub-Directory-12019.zip
---Sub-Directory-2
--------File1
--------Sub-Directory-22019.zip
I've tried a nested for loop but can't seem to get it. I've tried the for command with skip and dir in the set (IN), but can't get it to work.
I currently have the following script.
SET theYear=2019
For /D %%d in (*.*) do 7z a "%%d\%%d%theYear%.zip" ".\%%d\*"
This accomplishes it all except I don't know how to exclude the latest file (newest file according to last modification time) in each folder.
This batch file can be used for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FilesToIgnore=1"
set "theYear=%DATE:~-4%"
set "ListFile=%Temp%\%~n0.lst"
del "%ListFile%" 2>nul
for /D %%I in (*) do call :CompressFiles "%%I"
goto EndBatch
:CompressFiles
pushd %1
set "ZipFile=%~nx1%theYear%.zip"
for /F "skip=%FilesToIgnore% eol=| delims=" %%J in ('dir /A-D /B /O-D /TW 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /C:"%ZipFile%"') do >>"%ListFile%" echo %%J
if exist "%ListFile%" (
echo Compressing files in directory %1 ...
7z.exe a -bd -bso0 -i"#%ListFile%" -mx9 -scsDOS -- "%ZipFile%"
del "%ListFile%"
)
popd
goto :EOF
:EndBatch
endlocal
The batch file sets environment variable theYear dynamically from region dependent date string of dynamic environment variable DATE. Please execute in a command prompt window echo %DATE:~-4% and verify if output is the current year because of echo %DATE% outputs current local date with last four characters being the year.
The batch file ignores the FilesToIgnore newest files in each directory. Ignored is also the ZIP file if already existing from a previous execution of the batch file. The ZIP file is never included in number of FilesToIgnore because of filtered out already by findstr which filters output of command dir which outputs the file names without path in current directory ordered by last modification time with newest files output first and oldest files output last.
Please read help of 7-Zip for the used switches and parameters.
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 /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
popd /?
pushd /?
set /?
setlocal /?
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.
Update: 7-Zip version 19.00.0.0 outputs a warning and creates an empty ZIP file in each subdirectory on using the command line as written below and used initially in batch file. I first thought this is a bug of 7-Zip version 19.00.0.0 because of this version should support also -- according to its help and 7-Zip version 16.04.0.0 works on using the command line:
7z.exe a -bd -bso0 -mx9 -scsDOS -- "%ZipFile%" "#%ListFile%"
It was necessary to remove -- from this command line to get it working with 7-Zip version 19.00.0.0.
So I reported this issue and the author of 7-Zip quickly replied explaining why the usage of -- results in searching for a file starting with # in file name since 7-Zip version 19.00.0.0:
We need some way to add #file and -file names from command line.
So -- stops # and - parsing, and 7-Zip searches exact names.
It's more safe to use -i#listfile instead.
So I updated the batch file code and specify the list file with option -i which is the most safe method to specify a list file.
The following code is completely untested, so please be careful when executing:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "ROOT=Directory-Parent" & rem /* (set this to `%~dp0.` to specify the parent directory of the
rem batch file, or to `.` to for current working directory) */
set "YEAR=2019" & rem // (set the year just as a constant as it is unclear where to get it from)
set "MOVA=" & rem // (set this to `-sdel` if you want the files to be moved into the archive)
rem // Interate through the current working directory:
for /D %%d in ("%ROOT%\*.*") do (
rem // Clear exclusion parameter for `7z`, reset flag that indicates if there are files left:
set "EXCL=" & set "FLAG="
rem /* Iterate through all files in the currently iterated directory, sorted from
rem oldest to newest (`/O:D`), regarding the last modification date/time (`/T:W`);
rem the `findstr` part is to exclude the archive file itself if already present: */
for /F "delims= eol=|" %%f in ('
dir /B /A:-D /O:D /T:W "%%~d\*.*" ^| findstr /V /I /X /C:"%%~nxd%YEAR%.zip"
') do (
rem // Exclusion parameter is not yet set in first loop iteration:
if defined EXCL set "FLAG=#"
rem // Exclusion parameter becomes set at this point:
set "EXCL=-x!"%%f""
)
rem /* Flag is only set if there is one more file besides the one to exclude,
rem meaning that there are at least two files in total: */
if defined FLAG (
rem // Store folder information in variables to avoid loss of potentially occurring `!`:
set "FOLDER=%%~fd" & set "NAME=%%~nxd"
rem /* Toggle delayed expansion in order to be able to read variables that have been
rem set within the same block of parenthesised code (namely the `for` loops): */
setlocal EnableDelayedExpansion
rem // Execute the `7z` command line with dynamic parameters:
ECHO 7z a -bd %MOVA% !EXCL! -x^^!"!NAME!%YEAR%.zip" "!FOLDER!\!NAME!%YEAR%.zip" "!FOLDER!\*.*"
endlocal
)
)
endlocal
exit /B
I preceded the (potentionally dangerous) 7z command line by ECHO, just for safety purposes.

Append to a filename last modified date and time with a batch file

I am trying to copy all *.csv files from a folder to another folder, but while copying I need to add modified date and time of file to filename. For example, if filename is Test.csv and it was modified on 11/21/2018 15:01:10 output should be Test11-21-201815_01-10.csv. I found a script to add current timestamp to it, but I need to add modified date of file. You can see it below:
#echo off
set Source=C:\csvtest
set Target=C:\csvtest\csvtest\Archive
FOR /f "tokens=1-8 delims=/.:- " %%A in ("%date%%time%") DO (
SET Month=%%B
SET Day=%%C
SET Year=%%D
SET Hours=%%E
SET Minutes=%%F
SET Seconds=%%G
SET All=%%B-%%C-%%D_%%E-%%F-%%G
)
FOR %%i IN ("%Source%\*.csv") DO (
COPY "%%i" "%Target%\%%~Ni %All%.csv")
Thanks in advance for your help.
There are some examples here on SO for appending a date,
but I'd use PowerShell as a tool to accomplish this (wrapped in batch).
:: Q:\Test\2018\11\23\SO_53450598.cmd
#echo off
set "Source=C:\test"
set "Target=C:\test\Archive"
PowerShell -Nop -C "Get-ChildItem '%Source%\*.csv'|Copy-Item -Destination {'%Target%\{0} {1:MM-dd-yyyy_HH-mm-ss}.csv' -f $_.BaseName,$_.LastWriteTime} -WhatIf"
If the output looks OK, remove the -WhatIf at the end.
Here is a slightly faster way in batch file that uses delayedexpansion:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1-2" %%a IN ('forfiles /M file.ext /C "cmd /C echo #fdate #ftime"') do (
set line1=%%a
set line2=%%b
set line1r=!line1:/=-!
set line2r=!line2::=-!
rename "file.ext" "file!line1r!!line2r!.ext"
)
rem NOTE: Date format is DD-MM-YYYY. Time format is HH-MM-SS.
forfiles /M file.ext /C "cmd /C echo #fdate #ftime" runs the command (/C) for the file specified in /M option (file.ext).
"cmd /C echo #fdate #ftime" opens a new cmd and carry out the command specified by string and then terminates it.
#fdate is the last modified date of the file and #ftime is the last modified time of the file.
We set variables line1 and line2 for each of #fdate and #ftime and then we make some format changes to them.
Finally, we rename file.ext to fileDD-MM-YYYYHH-MM-SS.ext.

Batch File Adding Space to Variable

#ECHO OFF
CLS
REM Start Backup
TITLE Backup
SETlocal EnableDelayedExpansion
REM Capture the date/time(right down to the second) and then assign it to a variable
SET yy=%date:~-4%
SET dd=%date:~-7,2%
SET mm=%date:~-10,2%
SET newdate=%dd%%mm%%yy%_%Time:~0,8%
SET newdate=%newdate::=%
SET foldername=svetlana_backup_%newdate%
REM Variables
SET drive=R:
SET sevenZip=%USERPROFILE%\7z.exe
SET destination=R:\Backup
ECHO Running Backup Batch File
ECHO Please Plug in %drive%
PAUSE
ECHO %foldername%
MKDIR %destination%\%foldername%
FOR /F "tokens=1,2 delims=," %%i IN (backuplist.txt) DO (
SET completeSource=%%i
SET completeDestination=%destination%\%foldername%\%%j
ECHO Source: "!completeSource:"=!"
ECHO Destination:"!completeDestination:"=!"
MKDIR "!completeDestination:"=!"
XCOPY "!completeSource:"=!" "!completeDestination:"=!" /E /F
)
REM Zip the folder using the 7z command line utility
%sevenZip% a -tzip %destination%\%foldername%.zip %destination%\%foldername%
REM Remove the unzipped backup folder
RMDIR /Q /S %destination%\%foldername%
PAUSE
EXIT
This is a backup batch file that I've been using for last couple of days. It worked well up until this morning. For some reason, when it creates the variable foldername, it contains a space in the string where there was none before. It ends up like this:
svetlana_backup_22092016_ 93829
The space between the dash and the 93829 was never there before until today for some reason. How would I remove it and prevent it from happening again?
You can parse the file-/foldername like this
set foldername=%foldername: =%
This will replace all spaces with an empty string
The problem was likely caused because the test was run at a time where the hour contained just one digit. With that %Time:~0,8% will output the time including an extra space, as the time will be stored like this: 9:38:29 which are 7 characters and you read the last 8 ones.

Give Date Time on Bat File & Dynamic Path

I Hae Create BAT File
#ECHO OFF
"C:\Program Files\Microsoft SQL Server\100\DTS\Binn\dtexec.exe" /FILE "D:\New folder (2)\xslttosql\SSIS-BSMS\SSIS-BSMS\SSIS-BSMS\Package6.dtsx" /REP P >> "D:\TRX_Value.log"
exit
but i Want to make the Output which D:\TRX_Value.log path Changed Dynamically and give time information on the file name like D:\TRX_Value-20130307-144650.log which mean 2012/03/07 14:46:50
So is it possible? What kind of script should I write?
Dealing with dates is somewhat tricky in BAT files.
A simple solution is to use WMIC LocalTime command which returns the current date and time in a convenient way to directly parse it with a FOR command. Try something similar to this:
#ECHO OFF
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
SET /A DT=%%F*10000+%%D*100+%%A
SET /A TM=%%B*100+%%C
SET FDT=%DT%-%TM%
)
ECHO "c:\progs\dtexec" /FILE "d:\fldr\pack.dtsx" /REP P "d:\logs\tr%FDT%.log"
check the result and correct the execution line to fit your reqs
I like PA's suggestion to use WMIC, but there is a much simpler WMIC implementation.
The OS alias has the localDateTime property in almost the exact format you want:
YYMMDDhhmmss.ffffff-zzz
where ffffff is fractional seconds, and zzz is time zone information. Simple substring operations provide the desired date and time format.
#echo off
setlocal
set "ts="
for /f "skip=1" %%A in ('wmic os get localDateTime') do if not defined ts set "ts=%%A"
... your exe call ... >>"D:\TRX_Value-%ts:~0,8%-%ts:~8,6%.log"
Just because I like a challenge, here's a batch script / JScript hybrid script that'll format your timestamp the way you want. Save this with a .bat extension.
#if (#X)==(#Y) #end /* (batch + jscript hybrid script init)
:: *** Batch script *****
#echo off
setlocal
for /f %%I in ('cscript /nologo /e:jscript "%~f0"') do set "ts=%%I"
"C:\Program Files\Microsoft SQL Server\100\DTS\Binn\dtexec.exe" /FILE "D:\New folder (2)\xslttosql\SSIS-BSMS\SSIS-BSMS\SSIS-BSMS\Package6.dtsx" /REP P >> "D:\TRX_Value-%ts%.log"
exit /b
:: *** JScript script *****/
var d = new Date();
WScript.echo(d.getFullYear() + /\d{2}$/.exec('0' + (d.getMonth() + 1)) + /\d{2}$/.exec('0' + d.getDate()) + '-'
+ /\d{2}$/.exec('0' + d.getHours()) + /\d{2}$/.exec('0' + d.getMinutes()) + /\d{2}$/.exec('0' + d.getSeconds()));
(dbenham is a master at this sort of stuff.)
Echo's the date and time into 2 temp files, then parses them into correct format, and uses them in your command.
#ECHO OFF
Set CURRDATE=%TEMP%\CURRDATE.TMP
ECHO %DATE% > %CURRDATE%
Set CURRTIME=%TEMP%\CURRTIME.TMP
ECHO %TIME% > %CURRTIME%
Set PARSEDATEARG="eol=; tokens=1,2,3,4* delims=/, "
Set PARSETIMEARG="eol=; tokens=1,2,3,4,5* delims=:,., "
For /F %PARSEDATEARG% %%i in (%CURRDATE%) Do SET YYYYMMDD=%%k%%j%%i
For /F %PARSETIMEARG% %%i in (%CURRTIME%) Do SET HHMMSS=%%i%%j%%k
"C:\Program Files\Microsoft SQL Server\100\DTS\Binn\dtexec.exe" /FILE "D:\New folder (2)\xslttosql\SSIS-BSMS\SSIS-BSMS\SSIS-BSMS\Package6.dtsx" /REP P >> "D:\TRX_Value-%YYYYMMDD%-%HHMMSS%.log" exit

Batch: Timestamp to UNIX Time

For all I know, Batch does not have a command that gives the UNIX time. The closest one I can find is %time%, which only displays the timestamp.
Is there a command, or set of commands in Batch with which you can get the UNIX time?
There's Richie Lawrence's batch library that has all those nifty handy scripts. The one you need is DateToSec (which uses GetDate and GetTime).
Here's a simplified script, that employs a little WMI:
#echo off
setlocal
call :GetUnixTime UNIX_TIME
echo %UNIX_TIME% seconds have elapsed since 1970-01-01 00:00:00
goto :EOF
:GetUnixTime
setlocal enableextensions
for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do (
set %%x)
set /a z=(14-100%Month%%%100)/12, y=10000%Year%%%10000-z
set /a ut=y*365+y/4-y/100+y/400+(153*(100%Month%%%100+12*z-3)+2)/5+Day-719469
set /a ut=ut*86400+100%Hour%%%100*3600+100%Minute%%%100*60+100%Second%%%100
endlocal & set "%1=%ut%" & goto :EOF
The result will be returned into the first parameter passed to GetUnixTime, i.e. %UNIX_TIME%.
For example:
1341791426 seconds have elapsed since 1970-01-01 00:00:00
Hope it helps!
create a .bat file called "getUtime.bat"
#echo off
echo WScript.Echo(new Date().getTime()); > %temp%\time.js
cscript //nologo %temp%\time.js
del %temp%\time.js
and call like this
"C:\>getUTime"
1430894237616
What about simple 1-line long C program returning UNIX timestamp? You can retrieve value from %errorlevel% in batch script.
#include <stdio.h>
#include <time.h>
int main(void)
{
return (int) time(NULL);
}
In my test in command prompt it worked:
C:\Users\dabaran\Desktop\cs50\src\C>.\time || echo %errorlevel% && set mytstamp=%errorlevel%
1419609373
C:\Users\dabaran\Desktop\cs50\src\C>echo %mytstamp%
1419609373
There's a really simple way of doing this in a single batch file with no external scripts, files, libraries, etc.
<!-- :
for /f "tokens=* usebackq" %%a in (`start /b cscript //nologo "%~f0?.wsf"`) do (set timestamp=%%a)
echo %timestamp%
pause
exit /b
-->
<job><script language="JavaScript">
WScript.Echo(new Date().getTime());
</script></job>
The way it works is, code for a batch script AND code for a JS file are contained in the same .cmd or .bat file. you can force cscript to run the batch file as a script by commenting out the batch code and the : after the first line means batch will ignore it and run the batch code directly. so there you go!
There is no batch command for returning UNIX time. Your only options would be to write a program which could be run from a batch file that would return the UNIX time, or you could use the Windows PowerShell.
By far best solution is to download a freestanding date.exe unix-port.
Recommend that you rename it to unixdate.exe, to avoid conflict with MS Date command.
Get it from here
download & unzip. As far as I know, all the utilities are 'portable', that is, they don't require any installation program for them to work. I've only used a few (rm.exe & date.exe).
Also, you can ReName the exe's in case they might match other system utils you already have
Find the actual executable ports in the subfolder (usr\local\wbin)
To get HELP info type the command followed with --help (must spell help in lowercase)
Example:
((PROMPT)):unixdate +%Y%M%d
20141704
((PROMPT)):unixdate +%Y%b%d
2014Sep04

Resources