Using some great help (Create subdirectory under each directory containing a file) I added a \pre subdirectory in any directory that contained a .jpg photo.
I want to move any .jpg files from their current directory into the \pre subdirectory. The script I tried is:
FOR /R c:\temp %G IN (*.JPG) DO pushd %~dpG && if exist *.jpg move *.jpg pre\ && popd
The script moved the .jpg files. The problem is that the script moves the files then follows to the \pre directory and tries to do the move again.
The pre directories have been created using the script linked to in the first paragraph.
For example, directory A\B\C was processed to give A\B\C\pre. This script scans A/B/C and moves the .jpgs to \A\B\C\pre. It then follows the directory tree into A\B\C\pre and tries to move the .jpg files again
What about the following script:
#echo off
rem // Enumerate the directory tree:
for /D /R "C:\TEMP" %%G in ("*") do (
rem // Check whether current directory is not named `pre`:
if /I not "%%~nxG" == "pre" (
rem // Check whether there are files:
if exist "%%~G\*.jpg" (
rem // Create sub-directory called `pre`:
md "%%~G\pre" 2> nul
rem // Move files into the sub-directory:
move "%%~G\*.jpg" "%%~G\pre"
)
)
)
Or directly in command prompt:
#for /D /R "C:\TEMP" %G in ("*") do #if /I not "%~nxG" == "pre" if exist "%~G\*.jpg" md "%~G\pre" 2> nul & move "%~G\*.jpg" "%~G\pre"
The problem of doing the operation in the new "pre" directory is solved by getting the list of directories before enumerating over them.
It might be nice to have a one-liner command to do it, but this is getting a bit more complex than what is easy to do in a one-liner.
Here is a PowerShell script that will do it. If you are on a supported Windows platform, PowerShell will be available. This script requires PowerShell 5.1 or higher. If you cannot get to the current PowerShell, the code can be changed to make it work. When you are satisfied that the correct files will be moved, remove the -WhatIf from the mkdir and Move-Item commands.
=== Move-JpegToPre.ps1
$dirs = Get-ChildItem -Directory -Path "C:/src/t"
$extent = 'jpg'
foreach ($dir in $dirs) {
if (Test-Path -Path "$($dir.FullName)/*.$($extent)") {
if (-not (Test-Path -Path "$($dir.FullName)/pre")) {
mkdir "$($dir.FullName)/pre"
}
Move-Item -Path "$($dir.FullName)/*.$($extent)" -Destination "$($dir.FullName)/pre" -WhatIf
}
}
In a cmd.exe shell it can be invoked by:
powershell -NoLogo -NoProfile -File Move-JpegToPre.ps1
I suggest to use this batch file for the file moving task.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "C:\Temp\*.jpg" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /C:"\\pre\\" /C:"\\post\\"') do (
if not exist "%%~dpIpre\" md "%%~dpIpre"
move /Y "%%I" "%%~dpIpre\"
)
endlocal
FOR starts in background one more command process with %ComSpec% /c and the specified command line appended as additional arguments. So there is executed with Windows installed into C:\Windows in background:
C:\Windows\System32\cmd.exe /c dir "C:\Temp\*.jpg" /A-D /B /S 2>nul | %SystemRoot%\System32\findstr.exe /I /L /V /C:"\\pre\\" /C:"\\post\\"
DIR executed by the background command process searches
in directory C:\Temp and all its subdirectories because of option /S
just for files because of option /A-D (attribute not directory)
matching the wildcard pattern *.jpg
and outputs in bare format because of option /B
just the file names with full path because of option /S.
This list of file names is redirected from STDOUT (standard output) of background command process with redirection operator | to STDIN (standard input) of FINDSTR which searches
for lines containing case-insensitive because of option /I
either the literal string \pre\ or the literal string \post\
and outputs the inverted result because of option /V, i.e. the lines not containing \pre\ or \post\.
So FINDSTR is used here as filter to get from the list of *.jpg file names output by DIR with full path just those file names which do not have \pre\ or \post\ in their path to exclude the JPEG files which are already in one of the two subdirectories with name pre or post.
2>nul after the arguments of command DIR suppresses the error message output by DIR if it cannot find any *.jpg file name in C:\Temp and its subdirectories by redirecting the error message written to STDERR (standard error) to the device NUL.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with findstr with using a separate command process started in background.
FOR with option /F captures everything written to handle STDOUT of started command process by FINDSTR and processes this output line by line after started cmd.exe terminated itself. It is very important here to process a captured list of file names and do not iterate over one file name after the other returned by the file system because of the files matched by wildcard pattern *.jpg are moved during each loop iteration within the directory structure. So the directory entries matching *.jpg changes on each loop iteration and therefore it is required that a list of file names is processed loaded into memory before moving the files.
FOR with option /F ignores empty lines which do not occur here.
FOR with option /F would split up each line into substrings using normal space and horizontal tab as string delimiters and would assign just first space/tab delimited string to specified loop variable I if not starting with default end of line character ; in which case the line would be completely ignored like an empty line.
A file name with full path cannot start with ;. So default eol=; must not be modified here. But the line splitting behavior is counterproductive because of a full qualified file name can contain one or more spaces. For that reason the option delims= is used to define an empty list of string delimiters which disables completely the line splitting behavior.
Therefore each full file name output by DIR not containing \pre\ or \post\ in path as filtered out by FINDSTR is assigned to loop variable I one after the other.
It is checked next if there is for the current JPEG file a subfolder pre and this folder is created if not already existing. Then the current JPEG file is moved into the subdirectory pre with overwriting the file in pre with exactly the same file name.
So this batch file can be executed multiple times on C:\Temp as it ignores all *.jpg files in all subdirectories pre and post
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.
dir /?
echo /?
endlocal /?
findstr /?
for /?
if /?
md /?
move /?
setlocal /?
Related
As said in Q-title, I am trying to find a particular directory called Local State, but it could be spelled by some Apps as LocalState or Local State, anyone of which is surely present in every Apps' folder inside %USERPROFILE%, which I am trying to list out.
Now for that I had to write two lines, one for finding LocalState which works well, and it's as given:
pushd "%USERPROFILE%"
for /d /r %%h in (LocalState) do if exist "%%h" echo "%%h"
popd
But with the almost same line when I try to find Local State folder it doesn't show the paths as expected, as it adds extra quotes around the searched folder. See this:
pushd "%USERPROFILE%"
for /d /r %%h in ("Local State") do if exist "%%h" echo "%%h"
popd
gives this, which is weird, as any action can't be taken on this extra quoted path:
....
....
"C:\Users\<Username>\AppData\Local\BraveSoftware\Brave-Browser\User Data\"Local State""
"C:\Users\<Username>\AppData\Local\Google\Chrome\User Data\"Local State""
....
....
Now I am wondering is it possible with one line only I am able to search folder name like LocalState or Local State in the specified folder with batch script ? Something like this?
for /d /r %%h in ("Local? State") do if exist "%%h" echo "%%h"
And it would show paths in regular proper quoted format like:?
....
....
"C:\Users\<Username>\AppData\Local\BraveSoftware\Brave-Browser\User Data\Local State"
"C:\Users\<Username>\AppData\Local\Google\Chrome\User Data\Local State"
....
....
Or if that's not at all possible, then how can I find folder names with spaces and echo those paths in proper quoted format with no extra, unrequired quotes ?
Why do the FOR command lines not work as expected?
The strings LocalState and "Local State" are not interpreted by for as folder name to search for because of neither containing * nor ?. The command FOR searches only for non-hidden files or with option /D for non-hidden folders on specifying a wildcard pattern.
There was tried:
for /d /r %%h in (LocalState) do if exist "%%h" echo "%%h"
for /d /r %%h in ("Local State") do if exist "%%h" echo "%%h"
The command lines above result in searching recursively for directories (including hidden ones) and assign to the loop variable h each found directory with full path not enclosed in " concatenated with the specified string LocalState or "Local State".
Example: The current directory is C:\Temp with following directory structure:
C:\Temp
Development & Test(!)
Folder 2
The IF condition is executed with following strings assigned to loop variable h:
C:\Temp\LocalState
C:\Temp\Development & Test(!)\LocalState
C:\Temp\Folder 2\LocalState
C:\Temp\"Local State"
C:\Temp\Development & Test(!)\"Local State"
C:\Temp\Folder 2\"Local State"
The directory names 4 to 6 are problematic on as they contain themselves two double quotes resulting in executing the IF conditions with not correct specified names for file system entries – directory or file or reparse point – that makes no difference for IF in this case with no backslash at end.
Somebody might think this behavior of FOR does not make sense, but that behavior is useful in some use cases, for example on creation of a file with a specific name in each folder of a directory tree.
The problem here is that there cannot be added * at beginning or at end, i.e. use *LocalState or "Local State*" because of that can result in false positives. FOR would really search now for non-hidden directories of which name ends with LocalState or starts with Local State.
So the usage of the following command line would not be good:
for /d /r %%h in (*LocalState "Local State*") do echo "%%h"
What are possible solutions?
A very fast possible solution is:
for /F "delims=" %%h in ('dir "%USERPROFILE%\LocalState" "%USERPROFILE%\Local State" /AD /B /S 2^>nul') do echo "%%h"
There is started in background one more cmd.exe with option /c and the specified command line within ' appended as additional arguments.
DIR searches first
for just directories because of option /AD
with the name LocalState or the name Local State
in the specified directory %USERPROFILE% and
all its subdirectories because of option /S and
outputs just the fully qualified directory name because of the options /B (bare format) and /S.
DIR is so smart to search in each directory for both directories names. So the entire directory tree is searched by DIR only once for both directory names at the same time.
The started cmd.exe closes itself once DIR finished.
The cmd.exe instance processing the batch file captures all fully qualified folder names output by DIR and FOR processes them now line by line.
The FOR option delims= defines an empty list of delimiters to turn off the default line splitting behavior on normal spaces and horizontal tabs. That is required because of each folder name should be assigned completely one after the other to the loop variable h for further processing and not just the part up to first space character in a full folder name.
Other solutions are:
for /F "delims=" %%h in ('dir "%USERPROFILE%\Local*State" /AD /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /C:LocalState /C:"Local State"') do echo "%%h"
for /F "delims=" %%h in ('dir "%USERPROFILE%\Local*State" /AD /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /R /C:"Local *State"') do echo "%%h"
DIR searches in both cases for directories of which name starts with Local and ends with State (case-insensitive) recursively in specified folder %USERPROFILE%.
There is used FINDSTR on the first command line to filter out all false positive found directories of which fully qualified directory name does not end with the case-insensitive and literally interpreted string LocalState or Local State like Local & State.
There is used FINDSTR on the second command line to filter out all false positive found directories of which fully qualified directory name is at end not matched by the case-insensitive interpreted regular expression Local *State which matches LocalState and Local State and also Local State (two spaces) because of * is interpreted here as preceding character (the space) zero or more times. Please notice the difference. In a wildcard pattern * means any character zero or more times, but not here in the regular expression search string interpreted by FINDSTR where it means preceding character zero or more times.
The two solutions searching with DIR for the directories with a wildcard pattern and using FINDSTR to filter out false positive found directories are a bit slower than the solution using just DIR with the two directory names to search for.
In all provided solutions could be modified the DIR option /AD to /AD-L to ignore junctions and symbolic directory links (reparse points) and find just real directories.
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.
dir /?
echo /?
findstr /?
for /?
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on the FOR command lines to be interpreted as literal character 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.
This will work in a batch-file run under cmd on windows.
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
"(Get-ChildItem -Recurse -Directory -Filter 'Local*State').FullName"') DO (ECHO Directory name is %%~A)
Requires PowerShell 5.1 or later. Find your version with the command
$PSVersionTable.PSVersion.ToString() or (Get-Host).Version.ToString()
CMD. How do I check if a directory contains a folder/s (name is not specified)? Other files are ignored.
If this was in the case of any .txt file, it would kind of look like this :
if exist * .txt
How do I do it with "any" folder?
There are multiple solutions to check if a directory contains subdirectories.
In all solutions below the folder for temporary files referenced with %TEMP% is used as an example.
Solution 1 using FOR /D:
#echo off
set "FolderCount=0"
for /D %%I in ("%TEMP%\*") do set /A FolderCount+=1
if %FolderCount% == 0 (
echo Temporary files folder has no non-hidden subfolder.
) else if %FolderCount% == 1 (
echo Temporary files folder has one non-hidden subfolder.
) else (
echo Temporary files folder has %FolderCount% non-hidden subfolders.
)
pause
The problem with this solution is that FOR with option /D to search for directories matching the wildcard pattern * in specified directory for temporary files ignores the directories with hidden attribute set. For that reason the command SET with the arithmetic expression to increment the value of environment variable FolderCount by one on each each directory is not executed for a directory with hidden attribute set.
The short version of this solution without counting the folders:
#echo off
for /D %%I in ("%TEMP%\*") do goto HasFolders
echo Temporary files folder has no non-hidden subfolder.
goto EndBatch
:HasFolders
echo Temporary files folder has non-hidden subfolders.
:EndBatch
pause
The loop is exited with command GOTO on FOR has assigned first name of a non-hidden directory to the loop variable.
Solution 2 using FOR /F and DIR:
#echo off
set "FolderCount=0"
for /F "eol=| delims=" %%I in ('dir "%TEMP%" /AD /B 2^>nul') do set /A FolderCount+=1
if %FolderCount% == 0 (
echo Temporary files folder has no subfolder.
) else if %FolderCount% == 1 (
echo Temporary files folder has one subfolder.
) else (
echo Temporary files folder has %FolderCount% subfolders.
)
pause
FOR with option /F and a set enclosed in ' results in starting in background one more command process with %ComSpec% /c and the command line within ' appended as additional arguments. So executed is with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c dir "C:\Users\UserName\AppData\Local\Temp" /AD /B 2>nul
DIR executed by background command process searches
in specified directory for temporary files
just for directories because of option /AD (attribute directory)
with including also directories with hidden attribute set because of option /AD overrides the default /A-H (all attributes except attribute hidden)
and outputs them in bare format because of option /B which results in ignoring the standard directories . (current directory) and .. (parent directory) and printing just the directory names without path.
The output of DIR is written to handle STDOUT (standard output) of the started background command process. There is nothing output if the there is no subdirectory in the specified directory.
There is an error message output to handle STDERR (standard error) of background command process if the specified directory does not exist at all. This error message would be redirected by the command process executing the batch file to own STDERR handle and would be output in console window. For that reason 2>nul is appended to the DIR command line to suppress the error message in background command process by redirecting it from handle STDERR to device NUL.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR with option /F captures the output written to handle STDOUT of started background command process and processes the output line by line after started cmd.exe terminated itself after finishing execution of internal command DIR.
Empty lines are ignored by default by FOR which do not occur here.
FOR would split up the line by default into substrings using normal space and horizontal tab character as string delimiters and would assign just first space/tab separated string to specified loop variable I. This line splitting behavior is unnecessary here and is disabled for that reason by using option delims= which defines an empty list of string delimiters.
FOR would ignore also lines on which first substring after splitting a line up into substrings starts with default end of line character ;. The line splitting behavior is already disabled, but the name of directory can start unusually with a semicolon. Such a directory name would be ignored by FOR. Therefore the option eol=| defines the vertical bar as end of line character which no directory name can have and so no directory is ignored by FOR. See also the Microsoft documentation page Naming Files, Paths, and Namespaces.
The directory name assigned to loop variable I is not really used because of FOR executes for each directory name just command SET with an arithmetic expression to increment the value of the environment variable FolderCount by one.
The environment variable FolderCount contains the number of subfolders in specified directory independent on hidden attribute.
The short version of this solution without counting the folders:
#echo off
for /F "eol=| delims=" %%I in ('dir "%TEMP%" /AD /B 2^>nul') do goto HasFolders
echo Temporary files folder has no subfolder.
goto EndBatch
:HasFolders
echo Temporary files folder has subfolders.
:EndBatch
pause
The loop is exited with command GOTO on FOR has assigned first name of a directory to the loop variable.
Solution 3 using DIR and FINDSTR:
#echo off
dir "%TEMP%" /AD /B 2>nul | %SystemRoot%\System32\findstr.exe /R "^." >nul
if errorlevel 1 (
echo Temporary files folder has no subfolder.
) else (
echo Temporary files folder has subfolders.
)
pause
The output of DIR as explained above executed by cmd.exe processing the batch file is redirected from STDOUT of command process to STDIN (standard input) of FINDSTR which searches for lines having at least one character. The found lines are all lines with a directory name output by DIR. This search result is of no real interest and therefore redirected to device NUL to suppress it.
FINDSTR exits with 1 if no string could be found and with 0 on having at least one string found. The FINDSTR exit code is assigned by Windows command processor to ERRORLEVEL which is evaluated with the IF condition.
The IF condition is true if exit value of FINDSTR assigned to ERRORLEVEL is greater or equal 1 which is the case on no directory found by DIR and so FINDSTR failed to find any line with at least one character.
This solution could be also written as one command line:
dir "%TEMP%" /AD /B 2>nul | %SystemRoot%\System32\findstr.exe /R "^." >nul && echo Temporary files folder has subfolders.|| echo Temporary files folder has no subfolder.
See single line with multiple commands using Windows batch file for an explanation of the operators && and || used here to evaluate the exit code of FINDSTR.
Additional hints:
It would be good to first check if the directory exists at all before checking if it contains any subdirectories. This can be done in all three solutions above by using first after #echo off
if not exist "%TEMP%\" (
echo Folder "%TEMP%" does not exist.
pause
exit /B
)
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.
cmd /?
dir /?
echo /?
exit /?
findstr /?
for /?
goto /?
if /?
pause /?
set /?
DIR "your directory" /ad, for example DIR C:\Users /ad brings out all folders that are inside C:\Users
Displays a list of files and subdirectories in a directory.
DIR [ drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]
[/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]] [/W] [/X] [/4]
[drive:][path][filename]
Specifies drive, directory, and/or files to list.
/A Displays files with specified attributes.
attributes D Directories R Read-only files
H Hidden files A Files ready for archiving
S System files I Not content indexed files
L Reparse Points
If you just want to use the cmd.exe shell console to see if there are any directories:
DIR /A:D
If you want to check for it in a .bat file script:
SET "HASDIR=false"
FOR /F "eol=| delims=" %%A IN ('DIR /B /A:D') DO (SET "HASDIR=true")
IF /I "%HASDIR%" == "true" (
REM Do things about the directories.
)
ECHO HASDIR is %HASDIR%
I am using the following batch script while deletes files below a certain size.
#echo off
setlocal
:: Size is in bytes
set "min.size=100000"
for /f "usebackq delims=;" %%A in (`dir /b /A:-D *.*`) do If %%~zA LSS %min.size% del "%%A"
This works if I put the batch file inside the folder but it deletes the batch file also.
However how do I keep the batch file at a different position and specify the directory path explicitly?
The easiest solution is making the directory on which to delete files like C:\Temp\Test temporarily the active directory.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Size is in bytes
set "min.size=100000"
set "FullBatchFileName=%~f0"
pushd "C:\Temp\Test"
rem Do nothing if the command line above fails unexpected.
if errorlevel 1 goto EndBatch
for /F "eol=| delims=" %%I in ('dir * /A-D-H /B /OS 2^>nul') do if not "%FullBatchFileName%" == "%%~fI" if %%~zI LSS %min.size% ( del "%%I" ) else goto DeletionDone
:DeletionDone
popd
:EndBatch
endlocal
The DIR command line is executed by FOR in a separate command process started with cmd.exe /C in background and FOR captures all lines output by DIR to handle STDOUT. An error message output by DIR to handle STDERR on finding not any non-hidden file in current directory is redirected with 2>nul to device NUL to suppress it.
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The DIR option /OS results in getting the list of non-hidden files output by DIR ordered by size with smallest first and largest last.
FOR would skip lines starting with a semicolon which means it would skip files which file name starts with ; which is in general possible. This is avoided by specifying with eol=| the vertical bar as end of line character which no file name can contain.
FOR would split up the lines into substring using normal space and horizontal tab as delimiter and would assign only first substring to loop variable I. File names can contain one or more spaces. Therefore delims= is used to define an empty list of delimiters which disable the line splitting behavior completely and get assigned to loop variable I the entire file name.
The IF condition if not "%FullBatchFileName%" == "%%~fI" compares case-sensitive the full qualified name of the batch file (drive + path + name + extension) with full qualified name of current file. This condition is only true if the current file is not the currently running batch file.
The next IF condition if %%~zI LSS %min.size% compares the file size of current file converted to a 32-bit signed integer with the specified file size also converted to a 32-bit signed integer. This file size comparison fails on files with 2 GiB or more as such a large file exceeds the maximum positive 32-bit signed integer value 2147483647.
The FOR loop is exited with goto DeletionDone on first line having a file size equal or greater the specified minimum size because of all further files output by DIR have definitely a file size equal or greater than the specified minimum size because of being output ordered by size from smallest to largest.
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.
call /? ... explains %~f0 ... full qualified file name of argument 0 - the currently executed batch file.
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
popd /?
pushd /?
rem /?
set /?
setlocal /?
If you wanted to push ahead into PowerShell, the following script might work. When you are confident that the correct files will be deleted, remove the -WhatIf from the Remove-Item cmdlet.
$deldir = 'C:\Temp'
$minsize = 100000
$precious = 'Remove-UnderSize.ps1', 'Remove-UnderSize.bat'
Get-ChildItem -File -Path $deldir |
ForEach-Object {
if (-not ($precious -contains $_.Name)) {
if ($_.Length -lt $minsize) {
Remove-Item -Path $_.FullName -WhatIf
}
}
}
This script can be called from a cmd.exe bat file script.
powershell -NoProfile -File .\Remove-UnderSize.ps1
I have a folder where files are automatically created and I need every 5 minutes to copy the new files (that is, the files whose last modification was in the last 5 minutes).
:loop
for %a in (C:\test\*) do (
set FileDate=%~ta
)
timeout /t 300
goto loop
That's the way I have found to get date of file but I don't know how to compare and get the current date less 5 minutes.
(The copy command is not necessary, because is via SSH and this problem is resolved).
In batch date time calculations are a very tedious task.
I suggest to use PowerShell (at least as a tool)
To get the files created in the current directory in the last 5 minutes.
This powershell command will output a dir-like listing:
Get-ChildItem -Path 'X:\path'|Where-Object {((Get-Date) - $_.LastWriteTime).TotalMinutes -le 5}
To restrict this to only the FullName you can append the pipe
| Select-Object -ExpandProperty FullName
or simply enclose the command in parentheses and append (...).FullName
(Get-ChildItem -Path 'X:\path'|Where-Object {((Get-Date) - $_.LastWriteTime).TotalMinutes -le 5}).FullName
Wrapped in a batch
:: Q:\Test\2018\11\08\SO_53206386.cmd
#Echo off
for /f "usebackq delims=" %%A in (`
powershell -Nop -C "(Get-ChildItem -Path 'X:\path' -File |Where-Object {((Get-Date) - $_.LastWriteTime).TotalMinutes -le 15}).FullName"
`) Do Echo %%A
Sample output of this batch (listing itself)
> SO_53206386.cmd
Q:\Test\2018\11\08\SO_53206386.cmd
The -File parameter requires PowerShell v3+ but can be replaced with another piped command
| Where-Object {!($PSISContainer)}
filtering out folders. (The opposite is -Directory or no ! for not)
#Echo off
for /f "usebackq delims=" %%A in (`
powershell -Nop -C "(Get-ChildItem -Path 'X:\path' | Where-Object {!($PSISContainer)}| Where-Object {((Get-Date) - $_.LastWriteTime).TotalMinutes -le 15}).FullName"
`) Do Echo %%A
Here is a completely different solution resulting in most likely the same behavior with the advantage that the last modification date of a file does not really matter. So if a file is copied into the observed folder, it is also processed even if its last modification time is not within the last X minutes. It uses the archive file attribute set by Windows automatically each time a file is created in a folder or the file is modified by a process.
#echo off
set "Folder=C:\test"
:loop
for /F "eol=| delims=" %%I in ('dir "%Folder%\*" /AA-D-H /B /ON 2^>nul') do (
%SystemRoot%\System32\attrib.exe -a "%Folder%\%%I"
echo Copy the file "%Folder%\%%I"
)
%SystemRoot%\System32\timeout.exe /T 300
goto loop
The command FOR executes the following command line in a separate command process started with cmd.exe /C in background.
dir "C:\test\*" /AA-D-H /B /ON 2>nul
The command DIR outputs
in bare format only file name and file extension because of /B
only non-hidden files with archive attribute set because of /AA-D-H
ordered by file name because of /ON (not really needed)
found in directory C:\test matching wildcard pattern *.
The error message output by DIR on not finding any directory entry matching these requirements is suppressed by redirecting it from handle STDERR to device NUL.
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
This output of DIR in separate command process is captured by FOR and processed line by line.
Empty lines are always skipped by FOR which do not occur here.
Lines (file names) starting with a semicolon are also skipped by default by FOR. This behavior is disabled by changing with eol=| the end of line character from default ; to vertical bar which no file name can have anywhere.
FOR splits up by default the line in substrings (tokens) using space/tab as delimiters and assigns just first space/tab delimited string to specified loop variable I. This behavior is not wanted here as file names can contain one or more spaces. For that reason delims= is used to specify an empty list of delimiters which disables the line splitting behavior.
So assigned to loop variable I is the file name with file extension as output by DIR without path.
The command ATTRIB is used to remove the archive attribute from current file for next iteration of the FOR loop. Then the file can be copied to a different location or processed otherwise not modifying its content.
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.
attrib /?
dir /?
echo /?
for /?
goto /?
timeout /?
The base directory has about 20 subdirectories. Each subdirectory has many files. I need to move all the files from specific subdirectories to a newly created subdirectory in base directory at once.
For example I have in base directory D:\Documents the following directories:
D:\Documents\12345\data\images\
D:\Documents\12345\test\
D:\Documents\12345\documents\
I need to move all the files under images into newly to create directory D:\Documents\images in base directory.
Can you please help me in this?
This small batch file makes the job:
#echo off
md D:\Documents\images 2>nul
for /F "delims=" %%I in ('dir D:\Documents\* /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /B /I /R /C:D:\\Documents\\..*\\images\\ 2^>nul') do (
move /Y "%%I" "D:\Documents\images\%%~nxI"
rd "%%~dpI" 2>nul
)
The batch file first creates the target directory with suppressing the error message output by MD if this directory already exists. It is expected by this batch file that it is possible to create this directory and move the files into this directory without any additional checks.
Command DIR searches in D:\Documents and all it subdirectories because of /S for just files because of /A-D (attribute not directory) and outputs them in bare format because of /B which means just the file name with file extension and in this case also with full path because of /S.
It is possible that DIR cannot find any file in entire D:\Documents directory tree. The error message output in this case to handle STDERR is suppressed by redirecting it to device NUL using 2>nul after command DIR.
This output by DIR is redirected as input for command FINDSTR used as filter. It runs a regular expression find searching for lines starting with D:\Documents\ having at least one more character before \images\ must be found too. So it ignores the files in directory D:\Documents\images\ in case of this directory already exists with files on starting the batch file. But it does not filter out files in for example D:\Documents\12345\data\images\Subfolder\ as this regular expression does not check if \images\ is found at end of path.
It is possible that FINDSTR does not find any line (file name) matching the regular expression. The error message output in this case is suppressed by using 2>nul after command FINDSTR.
The command line with DIR and FINDSTR is executed by FOR in a separate command process started with cmd.exe /C in background without a visible window. For that reason the redirection operators > and | must be escaped with ^ to be interpreted first as literal characters by the Windows command interpreter on parsing the entire FOR command line before execution of FOR.
The lines output by the command line with DIR and FINDSTR to handle STDOUT in separate command process is captured by FOR and then processed line by line. With delims= the default behavior of splitting each line up into tokens using space and horizontal tab as delimiters is disabled by specifying an empty delimiters list.
The command MOVE moves the found file to D:\Documents\images\ with overwriting a file with same name in that directory.
The command RD removes the directory of just moved file if this directory is empty now after moving the file. Otherwise on directory not yet being empty an error message is output by command RD to handle STDERR which is suppressed using once again 2>nul.
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.
dir /?
echo /?
findstr /?
for /?
md /?
move /?
rd /?
Read also the Microsoft article about Using Command Redirection Operators.