How to copy all files with .jpg extension to a new folder? - batch-file

I am trying to find all the pictures on my computer and copy them all to just 1 folder. Here is the command I am using in Admin level Command Prompt.
C:>dir /s /b *.jpg | findstr /v .jpg > AllPics
For some reason I get this output: "Access is denied."
What can I do to fix this?

List the full path names of the JPG files in the current directory and all subdirectories:
dir /s /b *.jpg
Redirect the standard output stream of the dir command to the standard input stream of the findstr command. Exclude any file that contains .jpg (case sensitive) in the full path name:
| findstr /v .jpg
The result of the previous action seems to be counter-intuitive as it will negate a lot of output generated by the dir command.
Write the standard output stream of the findstr command to a file called AllPics (without a file extension) in the current directory:
> AllPics
The current directory seems to be set to the root of the C: drive. Because administrator privileges are required to save files directly to the root of the C: drive, you'll receive the "Access is denied" error message.
As pointed out by TripeHound, the "Access is denied" error might be caused because there already exists a folder named AllPics on the root of the C: drive.
One way to get the desired result is to parse each JPG file to the xcopy command:
setlocal
set "files=c:\*.jpg"
set "destDir=c:\AllPics"
for /f "delims=" %%f in ('dir "%files%" /b /s') do (
xcopy "%%f" "%destDir%\"
)
I've added another variant of the script that alters the destination name of the file to be copied which prevents potentially overwriting any possible duplicates.
setlocal enabledelayedexpansion
set "files=c:\*.jpg"
set "destDir=c:\AllPics"
for /f "delims=" %%f in ('dir "%files%" /b /s') do (
for %%d in ("%destDir%\%%~nf*") do (
set /a count+=1
)
xcopy "%%f" "%destDir%\%%~nf!count!%%~xf*"
set count=
)
Due to delayed expansion, the last variant of the script is unable to handle files that contain carets (^) within their fully qualified path name.
When a command-line contains environment variables that are expanded at execution time (like the count variable in this script), the entire command-line seems to be parsed twice. The for-loop variables (%%f and variants thereof) will be expanded during the first parse, the count variable is expanded during the second parse. Because the for-loop variables are already expanded when the second parse takes place, any singular carets present in the values of the for-loop variables are swallowed by the parser and omitted from the final result.
Here is the revision of the script that should take care of the problem described:
setlocal enabledelayedexpansion
set "type=.jpg"
set "source=c:\"
set "dest=c:\AllPics"
for /r "%source%" %%f in ("*%type%") do (
for %%d in ("%dest%\%%~nf*") do (
set /a count+=1
)
set "source=%%f"
set "dest=%dest%\%%~nf"
xcopy "!source!" "!dest!!count!%type%*"
set count=
)

I do this with WinRAR. Archive files from different folders with recursive scan, then extract in one folder (with e option, not x which restores the directory tree).

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.

Batch rename of files including complete parent directory structure

I have quite an extensive folder structure with only one file in the deepest/last folder. File name: model.cgf
What I want is to have a command-line batch-file that renames all files, renaming them so they list their complete parent folder structure. And then copy all the files into one designated folder.
The copied files would act as a catalog. So I know, when viewing a file, it's exact location in the folder structure.
It would be awesome if the script could add only newer files when it is run again.
Here is an example of the current file/folder structure:
_All_Models
| |__Script.bat
|
|__Catalog
|
|__Models
|
|__SubFolder
| |__model.cfg
| |
| |__SubFolder
| | |__model.cfg
| |
| |__SubFolder
| |__SubFolder
| | |__model.cfg
| |
| |__SubFolder
| |__SubFolder
| |__SubFolder
| |__model.cfg
|
|__etc.
| |__etc.
|
|__etc.
Here is an example of what I want:
_All_Models
| |__Script.bat
|
|__Catalog
| |__SubFolder.cfg
| |__SubFolder_SubFolder.cfg
| |__SubFolder_SubFolder_SubFolder.cfg
| |__SubFolder_SubFolder.cfg
| |__SubFolder_SubFolder_SubFolder_SubFolder.cfg
| |__etc.
| |__etc.
| |__etc.
|
|__Models
|__etc.
|__etc.
|__etc.
What I can currently do is batch rename the file "model.cfg" into "parent-folder.cfg" and copy it into a designated folder. This will rename and consolidate all files, however I now am missing all previous parent folders and dont know where in the folder-structure the file is located.
I know very little about scripting, so I have done many searches to find something useful, but perhaps what I want is not possible.
This is what I came-up with:
CD Models
REM Rename
for /r %%D in (.) do (for /f "delims=" %%F in ('dir /b /A:-D "%%D"') do echo "%%D\%%F" "%%~nxD%%~xF")
for /r %%F in (*) do (for /f "delims=" %%D in ("%%~dpF.") do ren "%%F" "%%~nxD%%~xF")
REM Copy
for /r "F:\All_Models\Models" %%i in (*.cgf) do copy "%%i" "F:\All_Models\Catalog"
My Catalog folder will now list all files named as: SubFolder.cgf (which is not detailed enough)
The script also changes all filenames in the original folders, these should still be named: model.cgf
I'd appreciate any help on improving my script :)
Thanks!
I had already started creating a script before I saw Magoo's answer.
My answer is almost the same, except:
All path computations are relative to the location of the script, so no need to set source or destination directories
I eliminate the leading path prefix differently. My method will fail if the leading path contains the = character (unlikely a problem)
I copy the files instead of move, which I believe is the intent of the OP
I hide the result of the copy and ECHO the resultant name of the copied file
I transfer all needed paths to variables and then toggle delayed expansion on and off so as to protect any ! that may be present in any of the paths.
#echo off
setlocal disableDelayedExpansion
for /f "delims=" %%F in (
'dir /b /s "%~dp0Models\Model.cfg"'
) do (
set "old=%%F"
set "new=%%~pF"
setlocal enableDelayedExpansion
set "new=!new:%~p0Models\=!"
set "new=!new:\=_!"
set "new=!new:~0,-1!.cfg"
echo !new!
copy "!old!" "%~dp0Catalog\!new!" >nul
endlocal
)
I did not bother trying to only copy new files. Existing files in the catalog are simply overwritten. To properly determine if the file has changed you would need to use FC, which seems like a waste of time and effort.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\models\model.cfg" '
) DO (
SET "destination=%%~dpa"
SET "destination=!destination:*\models\=!"
SET "destination=!destination:\=_!"
ECHO MOVE "%%a" "%sourcedir%\catalog\!destination:~0,-1!.cfg"
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
The for loop delivers each model.cfg file-location to %%a in turn. The drive and path are assigned to destination, then the part up to models\ is replaced by nothing and the backslashes are transformed to underscores. Then build the actual destination, remembering that ~dp includes a final backslash (which is now an underscore) so remove it using the 0,-1 substring.
Note that this uses delayedexpansion, so be prepared for fun and games should the tree contain directories including ! in addition to the usual suspects.
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
This is a possible way:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=%~dp0Models"
set "_TARGET=%~dp0Catalog"
set "_MASK=model*.cfg"
set "_CHAR=_"
rem // Change into source directory:
pushd "%_SOURCE%" && (
rem /* List matching files by `xcopy /L` and
rem capture the result by `for /F`: */
for /F "tokens=2 delims=:" %%F in ('
xcopy /L /S /I "%_MASK%" "%TEMP%"
') do (
rem // Store relative path of currently iterated item:
set "ITEM=%%F"
setlocal EnableDelayedExpansion
rem // Split off file name from relative path:
set "PAR=!ITEM!|" & set "PAR=!PAR:\%%~nxF|=!"
rem // Build new name and process current item:
copy /Y "!ITEM!" "!_TARGET!\!PAR:\=%_CHAR%!%%~xF"
endlocal
)
popd
)
endlocal
exit /B
This approach makes use of the fact that xcopy returns the source paths relative to the root, /S recurses sub-directories and /L prevents copying but just lists files that would be copied without. A for /F loop captures that list of relative paths, gets the parent directories, replaces every path separator \ by _ to build the target file names and then copies each file to the destination. Already existing files become overwritten without prompt; to confirm instead, just replace /Y by /-Y. To move files instead of copying, replace copy by move, of course.
Here is one solution:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for %%I in ("%~dp0..\Models") do set "ModelsPath=%%~fI\"
for %%I in ("%~dp0..\Catalog") do set "CatalogPath=%%~fI"
for /F "delims=" %%I in ('dir "%ModelsPath%model.cfg" /A-D /B /S 2^>nul') do (
set "FilePath=%%~dpI"
set "FilePath=!FilePath:~0,-1!"
set "NewFileName=!FilePath:%ModelsPath%=!"
set "NewFileName=!NewFileName:\=_!%%~xI"
ren "%%I" "!NewFileName!"
if exist "%%~dpI!NewFileName!" (
%SystemRoot%\System32\robocopy.exe "!FilePath!" "%CatalogPath%" "!NewFileName!" /XO /R:3 /W:5 /NS /NC /NFL /NDL /NP /NJH /NJS >nul
if not errorlevel 1 echo Ignored older "%%I"
ren "%%~dpI!NewFileName!" "%%~nxI"
) else echo Failed to rename "%%I"
)
endlocal
This batch file works only if no folder or file name contains ! and folder path of Models folder does not contain anywhere =.
The batch file first determines absolute path to the directories Catalog and Models from batch file path. Please note that environment variable ModelsPath holds the absolute path of folder Models with a backslash at end while CatalogPath is without backslash at end.
Then command FOR with option /F runs in a separate command process started with %ComSpec% /c and the command line specified within '...' as additional arguments in background the command DIR. So executed is with C:\Windows being the Windows directory and C:\Temp\Models\ being assigned to ModelsPath:
C:\Windows\System32\cmd.exe /c dir "C:\Temp\Models\model.cfg" /A-D /B /S 2>nul
DIR searches in
folder C:\Temp\Models
and all its subfolders because of option /S
for files with name model.cfg with
excluding directories because of /A-D which by chance are also named model.cfg
and output the found files with just full qualified file name, i.e. path + file name + file extension, because of options /B and /S.
This output by DIR to handle STDOUT of started command process is captured by FOR and processed line by line after started cmd.exe terminated itself.
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.
The FOR option delims= disables line splitting behavior of FOR to get every full qualified file name always assigned completely to specified loop variable I.
First the file path of current model.cfg is determined without backslash at end.
Then then Models path (with backslash at end) at beginning is removed and remaining path is assigned to environment variable NewFileName. Next all backslashes in this remaining path are replaced by an underscore.
The current model.cfg is renamed to new file name before ROBOCOPY is used to copy this file with its new file name to folder Catalog if the source file does not already exist in destination folder or the source file is newer than the file with same name in destination folder.
A file cannot be renamed if it is opened by an application with file sharing permissions set to deny renaming of file while being opened by the application. This is the reason for the additional IF condition.
Last the current model.cfg is renamed back to this file name in its source folder.
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.
echo /?
endlocal /?
dir /?
for /?
if /?
ren /?
robocopy /?
set /?
setlocal /?
See also on SS64:
ROBOCOPY
ROBOCOPY Exit Codes

the system cannot find the path specified when running batch file

I am trying to move files after sorting the files from one folder to another folder but I am always getting this exception "The System cannot find the path specified"
Below is my batch command code:
setlocal EnableDelayedExpansion
set destinationFolder=C:\Test_Actual_Queue
rem Create an array with filenames in right order
for /f "tokens=*" %%f in ('dir /b "C:\Test Print Queue\" ^| sort') do (
echo %%f
move %%f %destinationFolder%
)
pause
I am able to sort and display the file names in console but when I try to move to the destination folder , I am getting the above mentioned exception.
Both the folder paths are correct.
I tried debugging and this is the data I am getting in the console:
C:\TestFoder>setlocal EnableDelayedExpansion
C:\TestFoder>set destinationFolder=C:\Test_Actual_Queue
C:\TestFoder>rem Create an array with filenames in right order
C:\TestFoder>for /F "tokens=*" %f in ('dir /b "C:\Test Print Queue\" | sort') do (
echo %f
move %f C:\Test_Actual_Queue
)
C:\TestFoder>(
echo data1.Print_Job
move data1.Print_Job C:\Test_Actual_Queue
)
data1.Print_Job
The system cannot find the file specified.
C:\TestFoder>(
echo data2.Print_Job
move data2.Print_Job C:\Test_Actual_Queue
)
data2.Print_Job
The system cannot find the file specified.
what am I doing wrong here?
Looking forward to your solutions. Thanks in advance.
The command DIR with the arguments /b and "C:\Test Print Queue\" outputs just the names of all non hidden files and directories in specified directory without path. The current directory on execution of the batch file is C:\TestFoder which is a different directory than C:\Test Print Queue. For that reason the command MOVE cannot find the file/directory to move stored in C:\Test Print Queue specified without path in current directory C:\TestFoder and outputs the error message.
The command DIR would output the file/folder names with full path if additionally option /S is used to search also in subdirectories.
One solution is specifying source path also on MOVE command line:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\Test Print Queue"
set "DestinationFolder=C:\Test_Actual_Queue"
set "CreatedFolder="
if not exist "%DestinationFolder%\" (
md "%DestinationFolder%" 2>nul
if not exist "%DestinationFolder%\" (
echo Error: Failed to create folder "%DestinationFolder%"
goto EndBatch
)
set "CreatedFolder=1"
)
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /ON "%SourceFolder%\*" 2^>nul') do (
echo Moving file "%SourceFolder%\%%I" ...
move "%SourceFolder%\%%I" "%DestinationFolder%\"
)
if defined CreatedFolder rd "%DestinationFolder%" 2>nul
:EndBatch
endlocal
pause
Command extensions are explicitly enabled as required for for /F although enabled by default. Delayed environment variable expansion is explicitly disabled as not needed for this task. Files with one or more exclamation marks in file name could not be successfully processed within the FOR loop if delayed environment variable expansion is enabled explicitly although not enabled by default and not needed here. Read this answer for details about the commands SETLOCAL and ENDLOCAL.
The batch file first creates the destination folder if not already existing with verifying if folder creation was successful.
The command FOR executes the command line
dir /A-D-H /B /ON "C:\Test Print Queue\*" 2>nul
in a background command process started with cmd.exe /C.
Command DIR outputs
just non hidden files because of /A-D-H which means all directory entries not having attribute directory or hidden set
in bare format because of /B which means just the file name with file extension and without file path
sorted by name because of /ON
found in directory C:\Test Print Queue matching the wildcard pattern * (any file).
It is possible that the source directory does not exist at all or does not contain any file matching the criteria. The error message output in these cases by DIR is suppressed by redirecting it from handle STDERR to device NUL.
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.
FOR with option /F as used here captures everything written to handle STDOUT of background command process and then processes the captured text line by line.
Empty lines are ignored by FOR, but DIR with the used options does not output empty lines at all.
Lines starting with ; would be also ignored by default by FOR. File names can start with a semicolon. For that reason option eol=| is used to change the end of line character from semicolon (default) to a vertical bar which a file name can't contain at all.
FOR would split up each line into substrings (tokens) using the default delimiters space and horizontal tab and would assign to loop variable I just the first space/tab delimited string. This splitting behavior is not wanted here and so option delims= is used to define an empty list of delimiters to disable the line splitting and get assigned to I always the entire file name even on containing one or more spaces. tokens=* could be also used to get entire line (= file name) assigned to I.
For each file output by DIR with name and extension, but without path, the name of the file is output and command MOVE is executed to move the file to destination folder without overwriting a file with same name in that folder because of option /Y is not used here.
Finally the batch file deletes the destination folder if it was created by the batch file and if it is still empty because there was no file to move at all.
Another solution would be changing the current directory to source directory.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
cd /D "C:\Test Print Queue" || goto EndBatch
set "DestinationFolder=C:\Test_Actual_Queue"
set "CreatedFolder="
if not exist "%DestinationFolder%\" (
md "%DestinationFolder%" 2>nul
if not exist "%DestinationFolder%\" (
echo Error: Failed to create folder "%DestinationFolder%"
goto EndBatch
)
set "CreatedFolder=1"
)
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /ON 2^>nul') do (
echo Moving file "%%I" ...
move "%%I" "%DestinationFolder%\"
)
if defined CreatedFolder rd "%DestinationFolder%" 2>nul
:EndBatch
endlocal
pause
If command CD fails to change the current directory to source directory because of not existing, the well known error message is output:
The system cannot find the path specified.
Then the batch file jumps to the label EndBatch to restore previous environment and halt batch file execution until user presses any key.
On successfully changing the current directory the batch file continues and with command ENDLOCAL the initial current directory C:\TestFoder is set again as current directory for the command process executing the batch file.
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.
cd /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
move /?
pause /?
rd /?
set /?
setlocal /?

Write list of files with relative path, to file, via batch script

I want to list all files (with relative path) in a folder with a specific sub-folder, and write that list to a text file. The folder is a network folder so I can not set it as current directory. All this via batch script.
So like this:
Folder structure:
\\OtherComputer\MyFiles\libs
--File1.dll
--File2.dll
\\OtherComputer\MyFiles\libs\Editor\
----File3.dll
I want to generate a file with the following text:
File1.dll
File2.dll
Editor\File3.dll
This is how far I have come:
SET LibPath=\\OtherComputer\MyFiles\
break >"%LibPath%metadata"
for %%F in (%LibPath%*.*) do (
echo %%F>>"%LibPath%metadata"
)
for %%F in (%LibPath%Editor\*.*) do (
echo Editor\%%F>>"%LibPath%metadata"
)
But this solution write the full path. I tried this to remove the path:
set str=%%F:%LibPath%=%
But it does not seem to handle variable SET or the %%F variable too well inside a for-loop.
Is it even possible? Would like to not have to write a C# executable for this.
Thanks in advance!
Try the following:
#echo off
setlocal enabledelayedexpansion
set "dir=\\OtherComputer\MyFiles\"
FOR /F "tokens=*" %%f IN ('dir /s /b /A-d "%dir%"') do (
set "full=%%f"
echo !full:*%dir%=!
)
setlocal enabledelayedexpansion, in addition to creating a localized environment, turns on delayed expansions of variables, which allows variables to be modified inside the for loop's body and used with their modified values. (see help set). Note that in order for a variable to be expanded dynamically, you must enclose it in !, not %; e.g., !full! instead of %full%.
Note: A side effect of enabling delayed expansion is that any ! characters are interpreted as part of a variable reference, resulting in potentially unwanted removal of ! chars. from strings, such as in echo hi!. To output a literal ! while delayed expansion is enabled, use ^^! in unquoted strings, and ^! in double-quoted strings. Furthermore, literal ^ chars. in double-quoted strings then have to be represented as ^^.
dir /s /b /A-d "%dir%" lists all files - and files only, due to excluding directories with /A-d - in the current subtree (/s), as paths only (b). Note that using /s implies that full paths are output.
set "full=%%f" sets aux. variable full to the absolute path being processed in the current loop iteration.
!full:*%dir%=! then strips the input dir.'s path from the absolute path using prefix string substitution, leaving the relative path desired (again, see help set).
Just to contrast this with a PowerShell (v3+) solution, which demonstrates how much more advanced PowerShell is compared to cmd.exe.:
$dir = '\\OtherComputer\MyFiles\'
(Get-ChildItem -File -Recurse $dir).FullName.replace($dir, '')
I have a way to to this with two bat files:
code1.bat: Looping through all the files in "C:\Mypath"
#echo off
FOR /F "tokens=*" %%G IN ('dir /s /b C:\Mypath\*.*') do (
CALL code2.bat %%G
)
code2.bat: removing the main path string
SET _var=%1
SET _endbit=%_var:*Mypath\=%
Echo %_endbit%
Probably can be done in one file... take a look at http://ss64.com/nt/
The xcopy commmand is capable of returning relative paths. If the /L switch is given, nothing is actually copied but all items are listed that would be copied without /L. The pushd command handles UNC paths correctly (type pushd /? in command prompt for details). So the following code snippet should do what you want:
#echo off
pushd "\\host\share\folder"
> "\path\to\listfile.txt" xcopy /L /Y /C /I /E ".\*.*" "%TMP%"
popd
The above code results in each line to be prefixed with .\. In addition, it returns a summary line like # File(s). The code below gets rid of all those artefacts:
#echo off
pushd "\\host\share\folder"
> "\path\to\listfile.txt" (
for /F "tokens=2 delims=:" %%I in ('
xcopy /L /Y /C /I /E "*.*" "%TMP%"
') do (
echo(%%I
)
)
popd
Here I changed the file pattern from .\*.* to *.* which results in outputs like Z:rel\path\to\item.ext (rather than .\rel\path\to\item.ext). The for /F loop parses the output of xcopy and removes everything up to the first :, so the drive letter Z: is deleted. Since the : is a forbidden character for file and directory names, it cannot appear in any of the paths. Since the summary line # File(s) does not contain any columns, it is not enumerated by for /F.

Iterating through folders and files in batch file?

Here's my situation. A project has as objective to migrate some attachments to another system.
These attachments will be located to a parent folder, let's say "Folder 0" (see this question's diagram for better understanding), and they will be zipped/compressed.
I want my batch script to be called like so:
BatchScript.bat "c:\temp\usd\Folder 0"
I'm using 7za.exe as the command line extraction tool.
What I want my batch script to do is to iterate through the "Folder 0"'s subfolders, and extract all of the containing ZIP files into their respective folder.
It is obligatory that the files extracted are in the same folder as their respective ZIP files. So, files contained in "File 1.zip" are needed in "Folder 1" and so forth.
I have read about the FOR...DO command on Windows XP Professional Product Documentation - Using Batch Files.
Here's my script:
#ECHO OFF
FOR /D %folder IN (%%rootFolderCmdLnParam) DO
FOR %zippedFile IN (*.zip) DO 7za.exe e %zippedFile
I guess that I would also need to change the actual directory before calling 7za.exe e %zippedFile for file extraction, but I can't figure out how in this batch file (through I know how in command line, and even if I know it is the same instruction "cd").
EDIT #1
I have already received some tips on ServerFault to the same question. Please see the answers at this link.
However, it extracted from the root (C:), and not from the given in parameter folder.
Anyone has an idea?
EDIT #2
It seems that batch script doesn't handle folder and file names containing a space character adequately. Can anyone confirm what I think?
EDIT #3
I need it to be fully recursive, since I don't know the directory structure against which this will be used.
EDIT #4.a
With #aphoria's solution, I'm almost there! The only problem is that it takes let's say File5.zip, retrieve the filename only to get File5, creates a subfolder File5 and extract the File5.zip to File5 subfolder, then, it wants to create a File5 subfolder in Folder 1, where it should instead want to create File1 subfolder, to stick with my example.
EDIT #4.b
As required, here's the code as it currently look:
#echo off
setlocal enableextensions enabledelayedexpansion
rem
rem Display instructions when no parameter is given.
rem
if "%1" equ "" (
echo Syntaxe : od.bat ^<directory mask>^
echo Exemple : od.bat *
goto :Eof
)
rem
rem Setting the PATH environment variable for this batch file for accessing 7za.exe.
rem
path=c:\temp;%PATH%
rem
rem Removing quotes from the given command line parameter path.
rem
set root=%1
set root=%root:~%1
set root=%root:~0,-1%
rem Searching directory structure from root for subfolders and zipfiles, then extracting the zipfiles into a subfolder of the same name as the zipfile.
for /F "delims==" %%d in ('dir /ogne /ad /b /s %root%') do (
echo Traitement du dossier : "%%d"
for /F "delims==" %%f in ('dir /b "%%d\*.zip"') do (
rem Getting filename without extension.
set subfolder=~n%f
mkdir "%%d\%subfolder%"
rem Extracting zipfile content to the newly created folder.
7za.exe e "%%d\%%f" -o"%%d\%subfolder%"
)
)
:Eof
endlocal
Ideas anyone?
My guess is that it digs one directory hierarchy at a time. Here's the deal. Consider we have a Folder A in Folder 1 (Folder 1\Folder A), then, it searches from Folder 1 through Folder 5, and comes back to Folder 1\Folder A, where the %subfolder% variable sticks with its last value.
Anyone's help is gratefully appreciated.
I'm not very familiar with the 7zip command-line options, so you will need to figure out the exact command for that, but the script below will take a fully specified path (spaces allowed) and print out the the folder name and .zip files contained within it.
#ECHO OFF
REM
REM Remove the double quotes from the front and end of the root path
REM
SET ROOT=%1
SET ROOT=%ROOT:~1%
SET ROOT=%ROOT:~0,-1%
ECHO %ROOT%
FOR /F "DELIMS==" %%d in ('DIR "%ROOT%" /AD /B') DO (
ECHO %%d
FOR /F "DELIMS==" %%f in ('DIR "%ROOT%\%%d\*.zip" /B') DO (
ECHO %%f
)
)
Run it like this:
MyScript.CMD "c:\temp\usd\Folder 0"
You should get output similar to this:
Folder A
File 1.zip
File 2.zip
Folder B
File 1.zip
File 2.zip
UPDATE
The code below will extract Folder A\File 1.zip to a new folder Folder A\File 1.
A few things to keep in mind:
In the first FOR loop, you need to have %ROOT% enclosed in double quotes to handle folders with spaces in the name.
Since you're SETting a variable inside the second FOR, you need to put SETLOCAL ENABLEDELAYEDEXPANSION at the beginning. Then, reference the variable using ! (for example, !subfolder!) to force expansion at runtime.
This line of your code set subfolder=~n%f should be this set subfolder=%%~nf
I put ECHO in front of the MKDIR and 7za.exe commands to test. Once you are sure it is doing what you want, remove the ECHO statement.
Here is the code:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
REM
REM Remove the double quotes from the front and end of the root path
REM
SET ROOT=%1
SET ROOT=%ROOT:~1%
SET ROOT=%ROOT:~0,-1%
ECHO %ROOT%
REM Searching directory structure from root for subfolders and zipfiles,
REM then extracting the zipfiles into a subfolder of the same name as the zipfile.
FOR /F "delims==" %%d IN ('dir /ogne /ad /b /s "%ROOT%"') DO (
ECHO Traitement du dossier : "%%d"
FOR /F "delims==" %%f IN ('dir /b "%%d\*.zip"') DO (
REM Getting filename without extension.
SET subfolder=%%~nf
ECHO mkdir "%%d\!subfolder!"
REM Extracting zipfile content to the newly created folder.
ECHO 7za.exe e "%%d\%%f" -o"%%d\!subfolder!"
)
)
ENDLOCAL

Resources