I want to try the bat file to copy my log to other space.
My code:
REM get date
FOR /F "tokens=1-4 delims=/ " %%a IN ("%date%") DO (SET _MyDate=%%d/%%b/%%c)
echo _MyDate: %_MyDate%
set _path= "D:\Logs\AddressBook Service"
set _path2= "E:\Logs_test\AddressBook Service"
forfiles /p %_path% /d -%_day% /m *.log /c "cmd /c xcopy #path %_path2%"
My question is How to solve the forfiles #path has spaces in folder path?
Like this: E:\Logs_test\AddressBook Service
set "_day=2" only my guess
set "_path=D:\Logs\AddressBook Service"
set "_path2=E:\Logs_test\AddressBook Service"
forfiles /p "%_path%" /d -%_day% /m *.log /c "cmd /c echo xcopy #path \"%_path2%\\\" /D /E /-Y"
Above code snippet with proper escaped " double quotes (surprisingly escaped using a backslash \" instead of common caret) should result in something like
xcopy "D:\Logs\AddressBook Service\some name.log" "E:\Logs_test\AddressBook Service\" /D /E /-Y
Note that operational xcopy is merely displayed for debugging purposes. Remove echo keyword no sooner than debugged.
Adding a trailing backslash to xcopy target folder (%_path2%\\) seems to be facultative (optional) supplement.
Finally, note double quotes in set "variablename=variable value" syntax.
Related
I know someone out there has a nice quick solution for this: I just believe I am missing something. I am slightly new to creating bat files. I have roughly 2,000 files with improper naming on a share drive.
The below bat gets me started but I need to have the new file name include spaces but when I try it gives an invalid syntax command even with the ' " '.
Line 3, 3.MRF, is where it is giving me the syntax error '-' is not a valid command.
#echo
forfiles /S /M "1.PURCHASE*.*" /C "cmd /c rename "1.PURCHASE*.*" "2.PURCHASE*.*""
forfiles /S /M "3.MRF*.*" /C "cmd /c rename "3.MRF*.*" "1.MRF - *.*""
forfiles /S /M "3.ACOMRF-*.*" /C "cmd /c rename "3.ACOMRF-*.*" "1.ACO-MRF-*.*""
forfiles /S /M "2.RECEIPT*.*" /C "cmd /c rename "2.RECEIPT*.*" "3.RECEIPT*.*""
forfiles /S /M "2.RECIEPT*.*" /C "cmd /c rename "2.RECIEPT*.*" "3.RECEIPT*.*""
:exit
#pause
Perhaps run a for loop instead, it just looks much better to start off with:
#echo off
for /r /d %%a in (*) do (
pushd "%%~a"
ren "1.PURCHASE*.*" "2.PURCHASE*.*"
ren "3.MRF*.*" "1.MRF - *.*"
ren "3.ACOMRF-*.*" "1.ACO-MRF-*.*"
ren "2.RECEIPT*.*" "3.RECEIPT*.*"
ren "2.RECIEPT*.*" "3.RECEIPT*.*"
popd
)
Here you need one loop that will pushd to each of the subdirectories, rename anything that matches the rename parameter.
I would suggest using String Manipulation within a simple for-loop.
#echo off
setlocal enabledelayedexpansion
FOR %%A IN (3.MRF*.*) DO (
SET name=%%A
rename "!name!" "!name:3.MRF=1.MRF - !"
)
Before:
3.MRF A.txt
3.MRF B.txt
3.MRF C.txt
After:
1.MRF - A.txt
1.MRF - B.txt
1.MRF - C.txt
Update
Made a more generic solution which lets you define all search and replace strings. Moreover it works on all subdirs now.
#echo off
setlocal EnableDelayedExpansion
PUSHD "%0\.."
REM <search_1>;<replace_1|<search_2>;<replace_2>|...|<search_n>;<replace_n>
SET SearchAndReplace=3.MRF - ~1.MRF - ;3.ACOMRF-~1.ACO-MRF-
REM Replace ; with \n
SET SearchAndReplace=!SearchAndReplace:;=^
!
REM iterate over search and replace tokens
FOR /F "tokens=1,2 delims=~" %%G IN ("!SearchAndReplace!") DO (
set search=%%G
set replace=%%H
FOR /F "usebackq delims=" %%I IN (`dir /S /B /A:-d "*!search!*" 2^>nul`) do (
set file="%%I"
REM hack to allow replace !replace! for !search! in !file!
FOR /F "delims=" %%J IN ("!search!") do (
FOR /F "delims=" %%K IN ("!replace!") do (
echo move !file! !file:%%J=%%K!
move !file! !file:%%J=%%K!
)
)
)
)
POPD
Set the SearchAndReplace variable as needed (see comment).
I want to write a batch that finds all docs less than 50 mb in c:\ and copy them in a folder but ignore system directory docs. I prefer it does not even search in the system dir.
Here is my batch that finds and copies all files less 50 mb in right directory but i can not make it to ignore system from searching or C:\Windows directory.
#ECHO off
:: variables
SET odrive=%odrive:~0,2%
SET backupcmd=xcopy /s /c /d /e /h /i /r /y
MKDIR "C:\Users\Documents\USBBackups\DOC\C"
forfiles /P C:\ /M *.DOC* /S /C "cmd /c if #fsize leq 50000000 echo #PATH " > "C:\Users\Documents\USBBackups\DOCC.txt"
FOR /F "tokens=*" %%a in (C:\Users\Documents\USBBackups\DOCC.txt) do xcopy %%a "C:\Users\Documents\USBBackups\DOC\C" /c /h /i /r /y
#ECHO off
There is no way to tell forfiles to exclude certain directories when switch /S is provided. You will have to write your own code that does that.
I would not use forfiles for that due to poor performance, but standard for instead:
#echo off
for /D %%D in ("%SystemDrive%\*.*") do (
if /I not "%%D"=="%SystemRoot%" (
pushd "%%D"
for /R %%F in ("*.doc?") do (
if %%~zF LEQ 50000000 (
echo %%F
)
)
popd
)
)
Here the root directory level is enumerated by for /D. All directories other than %SystemRoot% are enumerated recursively by for /R.
I changed the search pattern from *.doc* to *.doc? in order not to include files ending in .doc.lnk for example, which I guess you do not want to be retrieved.
Instead of the echo command you can directly place your xcopy command line with "%%F" provided as the copy source.
You can do the same directly in command prompt as a one-liner, like this:
for /D %D in ("%SystemDrive%\*.*") do #if /I not "%D"=="%SystemRoot%" pushd "%D" & (for /R %F in ("*.doc?") do #if %~zF LEQ 50000000 echo %F) & popd
I recommend not to walk through the entire directory tree and later filtering by something like findstr /V /I /L /B /C:"%SystemRoot%", because in that case you were wasting time enumerating a huge number of items which you ignore afterwards.
However, if you do want to rely on forfiles /S, the working command line looks like this:
2> nul forfiles /S /P "C:\\" /M "*.doc*" /C "cmd /C if #isdir==FALSE if #fsize LEQ 50000000 echo #path" | findstr /V /I /L /B /C:"\"%SystemRoot%"
Adapt this technique of using findstr to filter out certain names.
To see size of folders in Documents, excluding music, video, or pictures folders.
for /f "skip=3 tokens=3" %A in ('Reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v "Personal"') do set doc=%A
for /f "usebackq tokens=2* delims= " %i IN (`dir "%doc%" /a /s ^|findstr /i /v "\/"^|findstr /l /v "Pictures Music Video"`) DO #echo %j&echo.
However you could start the forfiles command in the c:\users or the particular users home folder (%userprofile%). You specify to start at c:\ which includes all folders.
forfiles /P %userprofile% /M .DOC /S /C "cmd /c if #fsize leq 50000000 echo #PATH "
forfiles /P c:\users /M .DOC /S /C "cmd /c if #fsize leq 50000000 echo #PATH "
The forfiles command establishes several variables, indicated by a leading #, which return data concerning the currently iterated item to the loop body.
All the variables related to the path and name of the iterated item return the value enclosed in "". Those are: #file, #fname, #ext, #path and #relpath.
So: how can you get rid of the enclosing double-quotes?
For example, the following code returns relative paths to text files in the given root directory:
forfiles /P "C:\root" /M "*.txt" /C "cmd /C echo #relpath"
Assuming that C:\root contains two files file1.txt and file2.txt, the output will be:
".\file1.txt"
".\file2.txt"
However, I want the list of files without the surrounding "".
I am working on Windows 7 64-bit.
One approach is to nest a for %I loop within the forfiles and use the %~I expansion -- use this code in a Command Prompt window:
forfiles /P "C:\root" /M "*.txt" /C "cmd /Q /C for %I in (#relpath) do echo %~I"
To use that code within a batch file you must double the %-signs:
forfiles /P "C:\root" /M "*.txt" /C "cmd /Q /C for %%I in (#relpath) do echo %%~I"
The returned list of files will be (relying on the sample files from the original question):
.\file1.txt
.\file2.txt
Another variant is to nest another forfiles in the body of the initial one, because forfiles removes (non-escaped) double-quotes within given strings like the command line after /C:
forfiles /P "C:\root" /M "*.txt" /C "cmd /C forfiles /P #path\.. /M #file /C \"cmd /C echo #relpath\""
Or alternatively (the doubled inner forfiles is intentional, this works around a bug -- see this post):
forfiles /P "C:\root" /M "*.txt" /C "forfiles forfiles /P #path\.. /M #file /C \"cmd /C echo #relpath\""
The inner forfiles will enumerate exactly one item, which is the one passed over by the outer loop. Since #relpath is already expanded when the inner loop is executed, the quotes are removed as they are not escaped.
So the returned list of files looks like (again taking the sample files from the original question):
.\file1.txt
.\file2.txt
The additional line-break between the lines is generated by forfiles. You can avoid that using redirection (dismiss forfiles output, but display only the echo output in the console window):
> nul forfiles /P "C:\root" /M "*.txt" /C "cmd /C forfiles /P #path\.. /M #file /C 0x22cmd /C > con echo #relpath0x22"
I remove the quotes like this:
#ECHO OFF
GOTO START
usage:
script.bat "*.txt" "c:\Documents"
script.bat "*.txt"
script.bat
If no arguments added it will crawl the current directory with wildcard mask (*)
Avoid root directory (c:\) because too many sub directories for the output console.
:START
IF "%~2"=="" (SET "_FD=%CD%") ELSE (SET "_FD=%~2")
IF "%~1"=="" (SET "_MA=*") ELSE (SET "_MA=%~1")
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq delims=" %%A in (
`forfiles /p %_FD% /s /m %_MA% /C "cmd /c ECHO #relpath"`
) DO (
SET "myfile=%%~A"
ECHO !myfile:~2!
)
ENDLOCAL
GOTO :EOF
results:
thumbnails\A0-1.jpg
thumbnails\new folder\img.jpg
I want to use the forfile command to delete all .frm files in some directories. But, I don't want to delete the *.frm files under a specific directory.
I have this, but i don't know how to put the name of the dir where i don't want to delete files:
forfiles /p D:\myfolder\ /s /m *.frm /c "cmd /c IF NOT DESIRE_DIR del #PATH"
Some help, please !
#for /f "delims=" %A in ('dir /ad /b^|findstr /l /v /i "Dirname1 Dirname2"') do #echo %A
This is also a lot quicker than forfiles. Forfiles is only really useful when listing files by date.
Put your folder names in Dirname1, Dirname2 to exclude them. Spaces mean or.
Remember in a batch file %A becomes %%A.
forfiles /p D:\myfolder\ /s /d -7 /m *.frm /c "cmd /c echo #path >> %temp%\temp.txt"
for /f "delims=" %A in ('findstr /i /v "list of excluded directories" ^< "%temp%\temp.txt"') do echo %A
Your /m was also in the wrong place and you would have seen a message telling you that.
I have a directory with many files and folders and I'd like to make symlinks of all files and folders in that directory to another folder but exclude one folder
Any suggestions?
#echo off
set source=c:\source\directory
set target=c:\target\directory
set exclude=DoNotLinkThisDirectory
forfiles /P "%source%" /C "cmd /c if #isdir==TRUE (if not #file==\"%exclude%\" mklink /d \"%target%\#file\" #path ) else ( mklink \"%target%\#file\" #path )"
EDIT - Updated to allow "easily" add of multiple excludes, using /G:file if findstr command filter the file/folder list
#echo off
set "source=c:\source\directory"
set "target=c:\target\directory"
set "exclude=%temp%\exclude.txt"
(
rem exclude files/dires with these strings into full path
echo .txt
echo pipe.cmd
rem escaped backslash and initial and final quotes to avoid partial matches
echo "c:\\source\\directory\\something.txt"
rem exclude thisNot file/directory from source directory
echo "%source:\=\\%\\thisNot"
)> "%exclude%"
forfiles /P "%source%" /C "cmd /c (echo #path|findstr /i /v /g:"%exclude%" >nul) && if #isdir==TRUE (mklink /d \"%target%\\\"#file #path) else (mklink \"%target%\\\"#file #path)"
del "%exclude%" > nul