This is the inverse of the "flatten" operation described in this question: Flattening a directory
I would like a batch script that will go through each file in a "flattened" directory and put them back into their original directories, creating the directories as necessary
So if the following files were in my folder:
images-nature-dcim001.jpg
images-nature-dcim002.jpg
images-dcim003.jpg
images-indoors-dcim004.jpg
It would produce the resulting directory structure, creating the directories and moving (or copying) the files into the correct folder.
images
dcim003.jpg
nature
dcim001.jpg
dcim002.jpg
indoors
dcim004.jpg
Note: the example uses hyphens to separate the directories, but they can be any character.
This works here. It creates the four files at the top and then moves them.
#echo off
type nul >images-nature-dcim001.jpg
type nul >images-nature-dcim002.jpg
type nul >images-dcim003.jpg
type nul >images-indoors-dcim004.jpg
for %%a in (*.jpg) do call :routine "%%a"
pause
goto :eof
:routine
set "a=%~1"
set "b=%a:-=\%"
for %%b in ("%b%") do (
md "%%~pb" 2>nul
move "%a%" "%%~pb\%%~nxb"
)
#ECHO OFF &SETLOCAL
FOR /f "delims=" %%a IN ("%cd%") DO SET "precur=%%~dpa"
FOR /f "delims=" %%a IN ('dir /b /s /a-d *.txt') DO (
SET "fname=%%~fa"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "nname=!fname:%precur%=!"
SET "nname=!nname:\=-!"
ECHO REN "!fname!" "!nname!"
ENDLOCAL
)
Here's the version I am using based on foxidrive's approach to getting the directory name. I didn't think of simply replacing delimiters with back-slashes.
#echo off
Setlocal EnableDelayedExpansion
rem // Directory Unflatten
rem // recursively unflattens directories
rem // and prepends the directory name to
rem // the filename
rem // Configuration options
rem // * Files to search for
set pattern=*jpg;*.png
rem // * Directory name delimiter
set delim=-
rem // Perform moving
for %%X in (%pattern%) do (
set A=%%X
rem // Replace delimiter with back-slash
set b=!A:%delim%=\!
rem // Not sure how to clean this up
for %%B in ("!b!") do (
if not exist %%~pB (
md "%%~dpB"
)
move "!A!" "%%~dpB%%~nxB"
)
)
Related
I have a script I've written to remove the first six characters and then replace the beginning of the filename with the parent folders name. It currently seems to work, but then continues cutting 6 characters at a time till nothing is left, then adds the parent name. Don't know how I can fix this.
Files are currently named SF-1.1~~~~~~~~.pdf , SF-2.3~~~~~~~.pdf, etc and I just want to remove that SF string including the numbers. The rename command hated the period so I have the code prior to the rename removing any periods other than the extension and making them spaces.
set mypath=%cd%
echo %mypath% (where %mypath% is the current directory that the batch file is sitting in)
for %%a in ("%~dp0\.") do set "parent=%%~nxa"
rem echo %parent%
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
for /r "%root%" %%a in ("*.?*.pdf") do (
set "filename=%%~na"
setlocal enabledelayedexpansion
for %%f in ("!filename:.= !") do (
endlocal
ren "%%~fa" "%%~f%%~xa"
)
)
del root
dir /b *.pdf > temp
for /f "delims=" %%a in (temp) do rename "*.pdf" "//////*.pdf"
del temp
dir /b *.pdf > temp
for /f "delims=" %%a in (temp) do ren "%%a" "%parent% %%a"
del temp
I'm trying to write a batch script to replace the filler XXXX in a given folder structure for future projects. The batch should be put in the folder and be run there.
e.g.:
New_Project_0XXXX
01_0XXXX_Misc
01_0XXXX_Archive
SomeOtherName
02_0XXXX_NewData
MoreOtherStuff
02_0XXXX_OtherStuff
and so on.
The filler is to be replaced with a user prompted project number. I've had this first shot at it, but the problem is, that it renames the first layer and then it can't find the others.
set /P oldString="To Replace:"
set /P newString="Replace with:"
call :rendirs %oldString% %newString%
:rendirs
for /f %%a in ('dir /s /ad /b "*%~1*"') do (call :rename %%a %~1 %~2)
:rename
set oldname=%~n1
call set newname=%%oldname:%~2=%~3%%
ren %oldname% %newname%
I've got the idea of cutting the for loop to 'dir /ad /b' so it doesn't involve the subfolders yet and recursively calling the :rendirs function for the subfolders, but it doesn't work.
:rendirs
for /f %%a in ('dir /ad /b' "*%~1*"') do (
call :rename %%a %~1 %~2
for /f %%i in ('dir /ad /b') do (
cd %%i
call :rendirs %~1 %~2
)
)
How do I make cd work inside the loop or how do I ensure the script can find the subdirectories?
You should use the move command, instead of ren, because it can rename full qualified pathnames.
Then the :rename block looks like
:rename
set oldname=%1
call set newname=%%oldname:%~2=%~3%%
move %old_fullname% %newname%
BUT, you still have the problem of the renaming order.
First the top level directory is renamed, then all others will fail.
To solve this, you could reverse the dir list
I would accomplish your task using the following script (see the explanatory remarks in the code):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0." & rem // (target root directory)
set "_MASK=%~1" & rem // (directory name pattern)
set "_SEARCH=%~2" & rem // (search string)
set "_REPLAC=%~3" & rem // (replacement string)
rem // Skip all actions if no search string is provided:
if defined _SEARCH (
rem /* Traverse directory hierarchy in reverse manner,
rem so lowest level directories come first: */
for /F "eol=| delims=" %%D in ('
dir /S /B /A:D-H-S "%_ROOT%\%_MASK%" ^| sort /R
') do (
rem // Store path and name of iterated directory:
set "DIRP=%%D" & set "NAME=%%~nxD"
rem // Toggle delayed expansion to avoide loss of `!`:
setlocal EnableDelayedExpansion
rem // Actually rename iterated directory here:
ren "!DIRP!" "!NAME:%_SEARCH%=%_REPLAC%!"
endlocal
)
)
endlocal
exit /B
Given it is named renaming.bat, it should be used with the following arguments, based on your sample data and assuming XXXX is to be replaced by 1234:
renaming.bat "*_0XXXX*" "_0XXXX" "_01234"
I am trying to copy thousands of image files listed in a text file from multiple folders to one folder. The script I have works if all the file names were different. How do I get it to rename duplicates or rename all of them? Either will work as the name isn't important.
Example list
G:\research_data\an\an01\DCIM\100MSDCF\DSC04450.JPG
G:\research_data\an\an01\DCIM\100MSDCF\DSC04076.JPG
G:\research_data\an\an01\DCIM\100MSDCF\DSC03141.JPG
G:\research_data\an\an01\DCIM\120MSDCF\DSC04840.JPG
G:\research_data\an\an02\DCIM\100MSDCF\DSC04450.JPG
G:\research_data\an\an02\DCIM\112MSDCF\DSC04076.JPG
G:\research_data\an\an03\DCIM\102MSDCF\DSC03141.JPG
G:\research_data\an\an03\DCIM\105MSDCF\DSC04450.JPG
G:\research_data\an\an03\DCIM\106MSDCF\DSC04076.JPG
code:
#echo off
for /f "tokens=* delims=" %%a in ('type "L:\an_2017\image_list.txt"') do xcopy /hrkvy "%%a" "L:\an_2017"
pause
I see the issue you're running into. Looks like you're trying to transfer images from various directories with some containing the same file names. If you wish to keep both files, you could use an FOR statement to read your text file and rename the file at hand to DSC{Count} from 1+.
Using enabledelayedexpansion we can use set /a count += 1 to count up one number and rename %%a to a number. Please keep in mind I'm using %%~xa to get the extension of each file from the textfile. More info here: Parameter Extensions
The script bellow will read all file locations in the image_list.txt file and will copy each item to it's target directory with a new name of DSC1-DSCinfinity based on how many items are in image_list.txt. This avoids any issue's with duplicate names in your text file.
#ECHO OFF
#setlocal enableextensions enabledelayedexpansion
rem configure directories
set "source=L:\an_2017\image_list.txt"
set "target=L:\an_2017"
rem rename files to DSC{Count}
set /a count = 1
for /f "tokens=* delims=" %%a in ('type "%source%"') do (
copy "%%a" "%target%\DSC!count!%%~xa"
set /a count += 1
)
goto :EOF
In my example below, I am not using the file as a source for the jpg's, though you can still change that it you want. Instead, I dir /s through your DCIM directory, find all jpg files. Then I test the destination directory to see if the file exists, if it does, I increment it with a (n) at the end, if it does not exist, I just copy the file. This way you will have files without numeric increments (duplciates) It will not add a numeric value to each file. We will only do this for duplicates.
#echo off
setlocal enabledelayedexpansion
set "source=G:\research_data\an\an01\DCIM\"
set "dest=L:\an_2017\"
set /a cnt=0
for /f "tokens=*" %%a in ('dir /S /B /A-D "%source%*.jpg"') do for /f "tokens=*" %%b in ('dir /B "%%a"') do if exist "%dest%\%%b" (
set "ext=%%~xa"
set "fname=%%~na"
if exist "%dest%\!fname!(!cnt!)!ext!" (set /a cnt=!cnt!+1)
set /a cnt=!cnt!+1
copy "%%a" "%dest%\!fname!(!cnt!)!ext!"
) else copy "%%a" "%dest%\%%b"
#echo off
setlocal
set "source=L:\an_2017\image_list.txt"
set "target=L:\an_2017"
for /f "delims=" %%A in (%source%) do (
if not exist "%target%\%%~nxA" (
copy "%%~A" "%target%\%%~nxA"
) else (
call :index "%%~A" "%target%\%%~nxA" "1"
)
)
exit /b
:index source, target, count
setlocal
set /a "cnt=%~3"
if exist "%target%\%~n2(%cnt%)%~x2" (
call :index "%~1" "%~2" "%cnt%+1"
) else copy "%~1" "%target%\%~n2(%cnt%)%~x2"
The source file is read line by line.
If the file is not found in the target folder, then a copy done.
If the file is found in the target, then the label :index
is called with arguments of source, target and the count of 1.
In the called label, cnt is set the value of the count.
If the indexed file is not found in target, then a copy is done.
If found in target, calls the label again until the indexed file
is not found in target and a copy is done.
If you prefer using type, then replace
(%source%) with ('type "%source%"').
Note: The index integer is 1 based and does restart from 1
for indexing and increments until the filename is not
in the target.
I have a folder containing many files named as such: JBMA_23456.docx, JMRI_21456.docx, CM_22554.docx, QUA_11224.docx. How do I create a sub-folder for each file bearing the same name as the file but without the .docx file extension? Additionally, I want to store the filename only as variables.
For example, I need to create a sub-folder named JBMA_23456 from the document
JBMA_23456.docx. Can anyone point me in teh right direction?
#echo off
for %%A in (*.docx) do if not exist "%%~nA" md "%%~nA"
This creates a folder with the same name as each .docx file.
View modifiers in for /? or in call /?. The n modifier is the name.
Path modifiers:
dpnx is drive, path, name and extension.
Here's an example batch file which attempts to perform the tasks as laid out in your question:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "BaseDir=C:\Users\Compo\Desktop\test"
Set "FileExt=.docx"
For /F "Delims==" %%A In ('Set var[ 2^>Nul') Do Set "%%A="
Set "i=0"
For /F "Delims=" %%A In ('Where "%BaseDir%":*%FileExt% 2^>Nul') Do (Set /A i+=1
Call Set "var[%%i%%]=%%~nA"
If Exist "%%~dpA%%~nA\" (Echo Sub-Folder %%~nA already exists in %BaseDir%
) Else (Set /P "=Creating sub-folder %%~nA in %BaseDir%"<Nul
MD "%%~dpA%%~nA">Nul 2>&1 && (Echo= was successful) || Echo= failed))
Set var[ 2>Nul
Pause
In order to use it, you would first ensure that the directory holding your files, (excluding any trailing backslash), is placed between the = and " on line 4, and the single file extension, (including the leading period, .), similarly on line 5.
It is not entirely clear what you are asking for...
Anyway, here is the code i made
echo off
chcp 65001
cls
for /f "usebackq delims=." %%0 in (`dir /b "*.docx"`) do (
set filename=%%0
md %filename%
)
cmd /k
It creates a new folder for every file. Feel free to ask if this was not what you expected
I need a batch file to create a process for a list of files in a directory.
The filename structure is, for example: 00000_AAA_132144_2012021.txt
I need the batch to:
1 - Create a folder name based on the numbers after the second underscore, as this is the only constant in the naming.
2 - Move the file into the new folder.
In the example of the above the batch would create a folder called 132144 and then move the file 00000_AAA_132144_2012021.txt into the folder
For a similar requirement I used the script Endoro created for me (below). Is it possible to modify this to meet my requirement?
#echo off &setlocal
for /f "delims=" %%i in ('dir /b /a-d *.PDF') do (
set "filename1=%%~i"
setlocal enabledelayedexpansion
set "folder1=!filename1:~11,6!"
mkdir "!folder1!" 2>nul
move "!filename1!" "!folder1!"
endlocal
)
If you know that the filenames will be the same length, you can do the following to get the numbers after the second underscore -
set filename=00000_AAA_132144_2012021.txt
set dirname=%filename:~10,6%
If the spacing may vary - you can do the following -
for /f "delims=_ tokens=3" %%a in ('echo %filename%') do set dirname=%%a
And yes, the script written for you seems to do essentially the same thing as what you're asking - I've edited it to do what you've asked -
#echo off
setlocal enabledelayedexpansion
for /f %%i in ('dir /b /a-d *.txt') do (
set "filename=%%~i"
for /f "delims=_ tokens=3" %%a in ('echo !filename!') do set folder=%%a
mkdir "!folder!" 2>nul
move "!filename!" "!folder!"
)
This will move all *.txt documents to a folder created based on the third section of the text files name. Note that this will cause problems if you have .txt documents in the directory that do not follow the same naming standard.
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
SET "destdir=c:\destdir"
FOR /f "delims=" %%a IN ('dir /b /a-d "%sourcedir%\*_*_*_*.txt" ') DO (
FOR /f "tokens=3delims=_" %%m IN ("%%a") DO (
ECHO MD "%destdir%\%%m"
ECHO MOVE "%sourcedir%\%%a" "%destdir%\%%m\"
)
)
GOTO :EOF
Endoro's routine selects .pdf files, you've specified .txt
Find filenames matching the mask, find the third _-separated token in the name, make that directory and then move the file.
The required commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO MD to MD to actually create the directories and change ECHO MOVE to MOVE to actually move the files.
Append 2>nul to suppress error messages (eg. when the directory already exists)
Append >nul to suppress report messages (eg. 1 file moved)