Find recently modified files on windows console - cmd

I need to check in cmd if there are specific files recently modified (90 min).
On linux, my command works well:
find /home/my_folder -type f -mmin -90 -name *.txt
On MS-DOS, I cannot find a way to filter regarding modification time:
forfiles /P directory /S

You can use the /C parameter:
/C command Indicates the command to execute for each file.
Command strings should be wrapped in double
quotes.
The default command is "cmd /c echo #file".
The following variables can be used in the
command string:
#file - returns the name of the file.
#fname - returns the file name without
extension.
#ext - returns only the extension of the
file.
#path - returns the full path of the file.
#relpath - returns the relative path of the
file.
#isdir - returns "TRUE" if a file type is
a directory, and "FALSE" for files.
#fsize - returns the size of the file in
bytes.
#fdate - returns the last modified date of the
file.
#ftime - returns the last modified time of the
file.
To include special characters in the command
line, use the hexadecimal code for the character
in 0xHH format (ex. 0x09 for tab). Internal
CMD.exe commands should be preceded with
"cmd /c".
Ex:- forfiles /S /M *.txt /C "cmd /c echo #path #file #fdate #ftime"
Think this might be helpful. You can use forfiles /? to see more help details.

Related

Extract line of text from .txt file using CMD?

was wandering if there is a way to extract a line of text which contains certain value from a .txt file using CMD. For example using "type filepath\example.txt" will open the whole file and in my case I am working trough a software which doesn't allow CTRL+F option and .txt files are massive.
Is there any way I could specify certain word in order to get that whole line of text or to open only .txt files which have that word within them. For example I have 1000 .txt files and all of them contain the same text but only one of them has a word "EXAMPLE" in it. Could I use some command to find and open that file using CMD.
Thank you.
I have 1000 .txt files and all of them contain the same text but only one of them has a word "EXAMPLE" in it. Could I use some command to find and open that file using CMD.
a) find the file(s) that have the desired string:
findstr /m "EXAMPLE" *.txt
b) find the file (assuming, only one contains the string; else it will open all matching files) and open the file in notepad:
for /f "delims=" %a in ('findstr /m "EXAMPLE" *.txt') do "%a"
c) find the one line that has the string:
findstr "EXAMPLE" *.txt
The findstr.exe solution from Stephen would be less typing. But, using Select-String allows the use of a much more complete implementation of regex. All supported Windows systems have PowerShell available. This works in a batch-file run by cmd on windows and at the command prompt. Given that this would likely be put into a batch-file, the amount of typing is not very significant.
#powershell.exe -NoLogo -NoProfile -Command ^
Get-ChildItem -Path '.\*.txt' ^| ^
ForEach-Object { Select-String -Pattern 'example' -Path $_ } ^| ^
Select-Object -Property Filename,Line
Not the most elegant alternative, I agree, and I am certain someone will tell me how it could be bettered. The key is it uses basic find a string (you can set as I have to be case insensitive) in a file then reports filename and line number, Line [9] in this case.
#forfiles /m *.txt /C "cmd /c (find /n /i \"For example\" "#file"1>nul) &&if %errorlevel%==0 (find /n /i \"For example\" "#file"2>nul)"
When used in a batch file it could look something like this, but see caveats below
Finder$.cmd
#echo off & Title Find wally String in a file
set "string=where's Wally"
if not "%1"=="" set "string=%~*"
forfiles /m *.txt /C "cmd /c (find /n /i \"%string%\" "#file"1>nul) &&if %errorlevel%==0 (find /n /i \"%string%\" "#file")"
echo/ & pause & exit /b
It is not perfect but note its not case sensitive (using /i), it can readily fail if *.txt files are not plain text and as written will only accept a short unquoted string of up to 9 words ( avoid " or other punctuation). It works in local directory with *.txt, but you could alter those as require to first say cd /d f:\mylogs and search *.log files.
Finally you asked to open the file thus we can simplify for that task to call an editor like notepad or with some fetteling one that accepts line numbers (but that is another question)
forfiles /m *.txt /C "cmd /c (find /n /i \"%string%\" "#file"1>nul) &&if %errorlevel%==0 (notepad.exe "#file")"
Everything below is related to unix bash terminal, so please install Linux Subsystems if you are using Windows. Or even Linux itself :)
You can open specific file in a text editor like Vim or Nano in terminal. They offer the "CTRL+F" function.
Below you can see me searching for the "gameId" keyword in the file game_stats.js, which I opened via $ vim game_stats.js.
P.S. To quite vim you need to type :q :)
Use grep command as advised in this answer https://stackoverflow.com/a/16957078/13212398
Example for the command that recursively searches for any .js or .txt files that contains "let" in the current directory (.).
$ grep --include=\*.{js,txt} -rnw -e "let" .
./this_test.js:18:let bob = new Person('Bob');
./this_test.js:19:let bill = new Person('Bill', bob);
./TUD-2Q-WDB/checkers-in-delft/public/javascripts/game_state.js:99: let pieces = []

Batch to move folders that are 30 days old using FORFILES

I am currently working that moves ONLY folders from one directory to a folder. The current bacth file I have created is as follows.
Set /p target=Select Target Destination:
ForFiles /P "C:\Batch test" /D -4 /C "CMD /C if #ISDIR==TRUE echo Move #FILE %target%" &Move #File %target%
pause
The problem I have is with using a target directory that has a space in it for instance "C:\Move Test". I was wondering if there was a way to still move folders to another directory that has a space in the name.
You can replace the double quotes with their hexadecimal equivalent 0x22:
ForFiles /P "C:\Batch test" /D -4 /C "CMD /C if #ISDIR==TRUE (echo Move #FILE 0x22%target%0x22 & Move #File 0x22%target%0x22)"
If you get problems with other characters you can also replace them; 0x26=&, 0x28=(, 0x29=).
Your command line looks quite strange, there are several mistakes:
ForFiles /P "C:\Batch test" /D -4 /C "CMD /C if #ISDIR==TRUE echo Move #FILE %target%" &Move #File %target%
What is wrong:
you are talking about 30 days of age, but you specify /D -4, although /D -30 was correct; note that /D checks for the last modification date, not for the creation date!
there is an echo in front of the (first) move command, so the move command is displayed rather than executed; to avoid that, simply remove echo;
there is a second move command after forfiles, as it appears behind the closing quotation mark of the forfiles /C part, and behind the commmand concatenation operator &; this is completely out of scope of forfiles, therefore #file was treated literally; the ampersand and that orphaned move command needs to be removed;
to answer your actual question: to aviod problems with spaces (or other special characters) appearing in file/directory paths, put quotation marks around them; but: since that part appears within the command string after forfiles /C, which is already quoted, you cannot simply use "", you need to escape them; there are two options in forfiles: 1. using \", and 2. using 0x22 (according to the forfiles /? help, you can specify characters by their hexadecimal codes in the format 0xHH, the code 0x22 represents a " character); I strongly recommend option 2., because in variant 1. there still appear " characters that could impact the command interpreter cmd as it is not familiar with the \" escaping (its escape character is ^);
Thus the corrected command line looks like this:
ForFiles /P "C:\Batch test" /D -30 /C "CMD /C if #ISDIR==TRUE Move #FILE 0x22%target%0x22"
For the sake of completeness, this is how option 1. would look like:
ForFiles /P "C:\Batch test" /D -30 /C "CMD /C if #ISDIR==TRUE Move #FILE \"%target%\""
Note that you do not need to quote the source here, because #FILE (like all path-related #-style variables) expand to already quoted strings.

How to get a list of files that are older than 3 days and may be several directories deep using a batch file

We have a backup directory that could have a folder structure up to 4 folders deep. Backups are automatically purged dependant on a sucessfull backup. The issue is that sometimes the backup routine falls over and we don't know that it has and no files are being backed up in some of the folders.
Can anyone shed some light on a script to be run via a batch file that would:
1) loop through all the folders
2) provide a list of all files that are older than 3 days
3) have the ability to state the file or folder names to be excluded from the report.
Thanks in advance,
Jonathan
You can pipe the FORFILES result to FINDSTR with the /V and /G:file options to filter out the files you want to ignore. You can embed the files to ignore directly in your batch script. The full path of each file should be used, with enclosing quotes to match the FORFILES output.
I use the /L option to force the search to use literal strings, the /X option to make sure the filter uses an exact match, and the /I option to make it case insensitive.
Note that #path represents the full path, including the file name. So #file is not needed.
Also, FORFILES will list folders, so you should exclude them using #ISDIR
#echo off
forfiles /p n:\ /m * /s /c "cmd /c if #isdir==FALSE echo #path" /d -3 | findstr /vixlg:"%~f0" > c:\temp\output.txt
exit /b
"n:\somePath1\someFileToIgnore1.ext"
"n:\somePath2\someFileToIgnore2.ext"
etc.
If you want to exclude all files within a specific folder, then you will need to modify the above script to use regular expressions, using \R instead of \L. You can construct a regular expression to specify a specific file, all files within a specific folder, or all files within a folder tree.
Backslash literals must be escaped as \\, and period literals escaped as \.. Excluding files within a folder uses [^\\]* to represent the files - it matches any string of characters except except backslash. Excluding a folder tree uses .* to match any string of characters to match both folders and files.
#echo off
forfiles /p n:\ /m * /s /c "cmd /c if #isdir==FALSE echo #path" /d -3 | findstr /vixrg:"%~f0" > c:\temp\output.txt
exit /b
"n:\\somePath1\\someFileToIgnore1\.ext"
"n:\\somePath2\\ignoreFilesInThisFolder\\[^\\]*"
"n:\\somePath3\\ignoreFilesInThisFolderTree\\.*"
etc.

Date and time a file was copied to a directory

Is there a way to see what time a file get copied to a directory? Looks like Date modified column in windows explorer shows the date and time when the file got created.
You could try checking this via the command line.
Here are some commands that may help.
Using 'dir'
This, for example, gives the last modified time of this file:
dir /T:W d:\test.pdf
And this gives the date/time for all files and sub-directories in the current one:
dir /T:W
Using 'forfiles'
Modified datetime for all files in current dir:
forfiles /C "cmd /c echo #file #fdate #ftime"
Or just the pdf files within the directory:
forfiles /M *.pdf /C "cmd /c echo #file #fdate #ftime"
Using 'cp' in linux
I don't know who useful this would be for you, but on Linux machines you can use this option when coping files:
$ cp --no-preserve=timestamps my-file.pdf my-copy.pdf
This way the copy will have its own creation time and won't depend on the original file.

Archive files with certain extension

So I need a Windows Script that I can tell it a directory to go through and it will parse all sub-directories and while in each subdir, will archive all files with a certain file extension and keep it in the same subdir, then move onto the next one.
What's the best way to go about this? Perl Automation Scripting, AutoIt?
Any sample code you guys can give me?
Perl is more powerful than batch scripts but since Perl is not included with windows it seems overkill for tasks such as this one. This should for example work:
FOR /R C:\hello\ %%G IN (*.txt) DO "c:\Program Files\7-Zip\7z.exe" a %%G.zip %%G && del %%G
Note that you cannot do this directly in the prompt, you must save it as a .bat file. It is of course also possible to allow the user to specify the paths and extensions with command line like this:
FOR /R %1 %%G IN (%2) DO "c:\Program Files\7-Zip\7z.exe" a %%G.zip %%G && del %%G
More information about FOR and other windows command line commands can be found here: http://ss64.com/nt/
This would then be run with:
test.bat C:\Hello\ *.txt
EDIT: This obviously requires you to have 7-Zip installed but it's pretty obvious where to change the code if you want to use some other zipper. Also keep in mind to always be Extremely careful when experimenting with scripts such as this. One small mistake could have it delete a lot of files, so you should always test it on a copy of the file system until you are absolutely sure it works.
FORFILES is included with Windows and may be more applicable than FOR to what you're trying to do:
FORFILES [/P pathname] [/M searchmask]
[/S]
[/C command] [/D [+ | -] {MM/dd/yyyy | dd}]
Description:
Selects a file (or set of files) and executes a
command on that file. This is helpful for batch jobs.
Parameter List:
/P pathname Indicates the path to start searching.
The default folder is the current working
directory (.).
/M searchmask Searches files according to a searchmask.
The default searchmask is '*' .
/S Instructs forfiles to recurse into
subdirectories. Like "DIR /S".
/C command Indicates the command to execute for each file.
Command strings should be wrapped in double
quotes.
The default command is "cmd /c echo #file".
The following variables can be used in the
command string:
#file - returns the name of the file.
#fname - returns the file name without
extension.
#ext - returns only the extension of the
file.
#path - returns the full path of the file.
#relpath - returns the relative path of the
file.
#isdir - returns "TRUE" if a file type is
a directory, and "FALSE" for files.
#fsize - returns the size of the file in
bytes.
#fdate - returns the last modified date of the
file.
#ftime - returns the last modified time of the
file.
To include special characters in the command
line, use the hexadecimal code for the character
in 0xHH format (ex. 0x09 for tab). Internal
CMD.exe commands should be preceded with
"cmd /c".
/D date Selects files with a last modified date greater
than or equal to (+), or less than or equal to
(-), the specified date using the
"MM/dd/yyyy" format; or selects files with a
last modified date greater than or equal to (+)
the current date plus "dd" days, or less than or
equal to (-) the current date minus "dd" days. A
valid "dd" number of days can be any number in
the range of 0 - 32768.
"+" is taken as default sign if not specified.
Below one way I would do it in AutoIt since you asked. Replace the MsgBox line with whatever code you need to do whatever it is your wanting to do. AutoIt is fun stuff!
#include <File.au3>
archiveDir(InputBox("Path","Enter your start path."))
Func archiveDir($rootDirectory)
$aFiles = _FileListToArray($rootDirectory)
For $i = 1 To UBound($aFiles) - 1
If StringInStr(FileGetAttrib($aFiles[$i]),"D") Then archiveDir($rootDirectory & $aFiles[$i] & "\")
MsgBox(0,"This would be your archive step!",'"Archiving" ' & $rootDirectory & $aFiles[$i])
Next
EndFunc
One solution could be:
my $dirCnt = 0;
traverse_directory('C:\Test');
sub traverse_directory{
my $directory = shift(#_);
$dirCnt++;
my $dirHandle = "DIR".$dirCnt;
opendir($dirHandle, $directory);
while (defined(my $file = readdir($dirHandle))){
next if $file =~ /^\.\.?$/; # skip . and .. ...
if (-d "$directory\\$file"){ traverse_directory("$directory\\$file"); }
if ($file =~ /\.txt/){ #find txt files, for example
print "$file\n"; #do something with the text file here
}
}
closedir($dirHandle);
}

Resources