I'm doing some BATCH scripting looping through files to copy. But I came to a problem where I need the path relative to the current .bat execution folder (%cd%)
So if I have files like this:
c:\games\batchTest\test.bat
c:\games\batchTest\subFolder1\test1.txt
How can I get just "subFolder1\test1.txt" so I can copy the file with the sub folder?
My current code:
for /r %%a in (*) do (
echo "%%a"
)
You can try this:
#Echo Off
Setlocal enabledelayedexpansion
For /r %%a In (*) Do (
Set p="%%a"
Echo !p:%__CD__%=!
)
The for /R loop always returns absolute paths, even if the (optional) given root directory behind /R is relative.
A possible way to get relative paths is to (mis-)use the xcopy command together with its /L option that prevents anything to be copied:
xcopy /L /S /I ".\*.*" "%TEMP%"
To remove the summary line # File(s) apply a filter using find using a pipe:
xcopy /L /S /I ".\*.*" "%TEMP%" | find ".\"
To process the returned items use a for /F loop:
for /F "eol=| delims=" %%F in ('
xcopy /L /S /I ".\*.*" "%TEMP%" ^| find ".\"
') do (
echo Processing file "%%F"...
)
If you just want to copy files including the sub-directory structure you do not even need the above stuff with for loops, you can simply use xcopy:
xcopy /S /I "D:\Source\*.*" "D:\Destination"
or robocopy:
robocopy /S "D:\Source" "D:\Destination" "*.*"
Related
I created a batch file that allow to move a file from a folder to another.
My issue is that my bat file should also browse source subfolders in order to find files that have a specific pattern.
Actually :
#ECHO ON
SET SourceDir=C:\Users\me\Documents\source
SET CopyDir=C:\Users\me\Documents\repository
SET FilePatterName=*pattern*.pdf
FOR %%A IN ("%SourceDir%\%FilePatterName%") DO (
ECHO F | XCOPY /Y /F "%%~A" "%CopyDir%\"
DEL /Q /F "%%~A"
)
GOTO EOF
For example : in my source folder, if i have sub1, sub2, sub3 folders and a sub1-1 folder in sub1, i would like to check each folders, check the files and move them without creating any folder in the repository
As per my comment, use for /r which will recurse through the directories:
for /R "%SourceDir%" %%A in ("%FilePatterName%") do...
if it feels too ugly then first pushd to the directory, then recursively search from there:
#Echo off
Set "SourceDir=C:\Users\me\Documents\source"
Set "CopyDir=C:\Users\me\Documents\repository"
Set FilePatterName=*pattern*.pdf
Pushd "%SourceDir%"
For /R %%a in ("%FilePatterName%") do (
Echo F | Xcopy /Y /F "%%~a" "%CopyDir%\"
Del /Q /F "%%~a"
)
Popd
Here's an alternative, using the same structure but robocopy instead of xcopy and del:
#Set "SourceDir=%UserProfile%\Documents\source"
#Set "CopyDir=%UserProfile%\Documents\repository"
#Set "FilePatterName=*pattern*.pdf"
#If Exist "%SourceDir%\" For /R "%SourceDir%" %%# In ("%FilePatterName%")Do #"%__AppDir__%Robocopy.exe" "%%~dp#." "%CopyDir%" "%%~nx#" /Mov>NUL 2>&1
If you really needed to see the filenames, I suppose you could include additional RoboCopy options like /FP, /NDL, /NS, /NC, /NJH and /NJS.
Currently I am iterating all files in a folder, currently I am in Sample folder and I am doing it like this:
#echo off
for /R %%a in ("*") do (
#echo %%a
)
pause
And it lists files like this:
C:\Users\-----\Desktop\Sample\mybat.bat
C:\Users\-----\Desktop\Sample\bin\1.dll
C:\Users\-----\Desktop\Sample\content\themes\2.css
What I want is to list the name but starting from current folder where I put the .bat file, i. e., it should look like this:
Sample\mybat.bat
Sample\bin\1.dll
Sample\content\themes\2.css
A nice way to return a list of files relative from the current directory is to use xcopy /L:
pushd "%~dp0.."
xcopy /L /S /I ".\Sample" "%TEMP%" | find ".\"
popd
To loop through all the returned items, use this:
pushd "%~dp0.."
for /F "delims=" %%F in ('
xcopy /L /S /I ".\Sample" "%TEMP%" ^| find ".\"
') do (
echo(%%F
)
popd
To remove the .\ prefix, use the following:
pushd "%~dp0.."
for /F "tokens=1* delims=\" %%E in ('
xcopy /L /S /I ".\Sample" "%TEMP%" ^| find ".\"
') do (
echo(%%F
)
popd
I have folder structure:
folder "1" that Contains "1.1" "1.2" "1.3"
folder "1.1" Contains "1.1.1" "1.1.2"
in the bat file :
cd %folderDir%
#echo off
call :treeProcess
goto :eos
:treeProcess
for /f "delims=" %%a IN ('dir /a:-d/b 2^>nul ') do echo "%%~fa" >>%pathDdfFile%
for /D %%d in (*) do (
echo %%d >>%pathDdfFile%
echo %%d
cd %%d
call :treeProcess
cd ..
)
goto :eof
:eos
cd \
I get:
1.1
1.1.1
1.1.2
1.2
1.3
but I need:
1.1
1.1\1.1.1
1.1\1.1.2
1.2
1.3
To get a list of the directories like you desire, you can do this:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
FOR /F "delims=" %%G IN ('DIR /S /B /A:D /O:N ^| SORT') DO (
SET tmp=%%G
ECHO !tmp:%CD%\=!
)
This will, if executed from within the folder 1, give you:
1.1
1.1\1.1.1
1.1\1.1.2
1.2
1.3
It works by removing the current directory from the output of the DIR /S /B command.
The simplest way to get relative paths is using xcopy /L, because it returns paths relative to the current directory in case a relative source path is given; /L tells to actually not copy:
xcopy /L /S /E /I /Y ".\*.*" "%TEMP%\"
To avoid the summary line ?? File(s), use a simple find command to filter it out:
xcopy /L /S /E /I /Y ".\*.*" "%TEMP%\" | find ".\"
This can finally be parsed by a for /F loop to iterate trough every single item:
for /F "delims=" %%I in ('
xcopy /L /S /E /I /Y ".\*.*" "%TEMP%\" ^| find ".\"
') do (
echo(%%I
)
The great advantage of this method is that the system accomplishes the path computations, hence you do not need to write extra code for something the system is anyway already able to do for you.
So no string manipulation activities are needed, delayed expansion is not required, which reduce the overall performance and might even be prone to errors particularly in special cases.
Hi all and thanks for the answers,
Firstly, I tried to find the answer to my problem but I did not find anything.
I have a tree of folders and sub-folders and I want to use 7zip to compress the files within those folders separately.
I have got this piece of code from this very website, it does what I want to get but it places the compressed files on the main folder:
set extension=.*
for /R %%a in (*%extension%) do "%sevenzip%" a -mx "%%~na.zip" "%%a"
I wonder if I can get a zip file of every file and have it in the sub-folder containing the source file. Or doing the process above and place every zip file inside the appropriate sub-folder.
I tried with a double 'For /d' but I was unable to get it:
cd /d %~dp0
rem 7z.exe path
set sevenzip=
if "%sevenzip%"=="" if exist "%ProgramFiles(x86)%\7-zip\7z.exe" set
sevenzip=%ProgramFiles(x86)%\7-zip\7z.exe
if "%sevenzip%"=="" if exist "%ProgramFiles%\7-zip\7z.exe" set
sevenzip=%ProgramFiles%\7-zip\7z.exe
if "%sevenzip%"=="" echo 7-zip not found&pause&exit
for /D %%O in (*) do (
for /R %%I in ("%%O\*") do (
"%sevenzip%" a -mx "%%~na.zip" "%%a"
:: rd /s /q "%%I" **Because I do not want to delete anything by now.
)
)
Again, thank you.
Alex.
If you have somewhat complex folder structure then you probably better use plain list from dir:
dir /a:-d /s /b /o
Just use its output in for:
for /f %%f in ('dir /a:-d /s /b /o') do (
echo %%f <-- %%f is a full path to a file, do something with it
)
Btw, 7zip has useful option -sdel to remove the source file when archive has been created successfully.
This is the final code:
#echo off
cd /d %~dp0
rem 7z.exe path
set sevenzip=
if "%sevenzip%"=="" if exist "%ProgramFiles(x86)%\7-zip\7z.exe" set sevenzip=%ProgramFiles(x86)%\7-zip\7z.exe
if "%sevenzip%"=="" if exist "%ProgramFiles%\7-zip\7z.exe" set sevenzip=%ProgramFiles%\7-zip\7z.exe
if "%sevenzip%"=="" echo 7-zip not found&pause&exit
#echo searching...
for /R %%I in (*) do (
"%sevenzip%" a -mx -mmt4 "%%I.7z" -r -x!*.bat "%%I"
)
del "Compressing_files_7zip.bat.7z"*
del *.7z.7z
del *.zip.7z
::::::::::::::::::::::::::For setting up shutdown 60' after the end of the process.Remove colons in the line below.
::shutdown.exe /s /t 3600
pause
Thanks all for the support, especially to Frost.
For a simpler version without using 7zip:
for /f %%f in ('dir /a:-d /s /b /o *.mdb') do (
zip -r -p "%%f.zip" "%%f"
)
I want to write a batch file that creates a folder (if it does not exist) and copies a certain file into that folder. So far so good.
The problem is that one folder in the path varies slightly from time to time, so a wildcard becomes necessary.
The following code works just fine but obviously misses to create the folder (Reports). So if the folder is not there, it simply does nothing.
for /r "c:\Users\%USERNAME%\AppData\Local\Packages" &&G in ("LocalState\acn\Reports") do #if exist %%G xcopy /s /i /y c:\temp\Reporting "%%G"
The full path is:
c:\Users\FSchneider\AppData\Local\Packages\“WILDCARD"\LocalState\acn\Reports\
Any idea?
Add /d switch in for to indicate you're looking for a directory, not a file
Add * and omit quotes in the wildcard to indicate it's actually a wildcard
No need for if exist now
for /d /r "%LocalAppData%\Packages" %%G in (LocalState\acn.*) do xcopy /s /i /y c:\temp\Reporting "%%G\Reports"
Next script could help.
#ECHO OFF
SETLOCAL enableextensions
set "_fldrtop=%USERPROFILE%\AppData\Local\Packages"
set "_fldrsub=LocalState\acn"
if not "%~1"=="" set "_fldrsub=%~1" :: my testing data, remove this line
set "_fldrlow=Reports"
if not "%~2"=="" set "_fldrlow=%~2" :: my testing data, remove this line
for /F "delims=" %%G in ('dir /B /AD "%_fldrtop%"') do (
if exist "%_fldrtop%\%%G\%_fldrsub%\" (
if exist "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\" (
echo echo "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\"
) else (
echo md "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\"
)
rem echo xcopy /s /i /y c:\temp\Reporting "%_fldrtop%\%%G\%_fldrsub%\%_fldrlow%\"
)
)
Output:
==>D:\bat\SO\31672436.bat
==>D:\bat\SO\31672436.bat "LocalState\Cache"
md "C:\Users\UName\AppData\Local\Packages\winstore_cw5\LocalState\Cache\Reports\"
==>D:\bat\SO\31672436.bat "LocalState\Cache" 2
echo "C:\Users\UName\AppData\Local\Packages\winstore_cw5\LocalState\Cache\2\"