I am working on writing a script that will create folders based on parts of file names. The problem is the Delim's are both the same. File names look like this: "Bacon-HunterBacon-00002" I am looking at using the first and second tokens to be the folder name. So the folder would be named Bacon-HunterBacon
#echo off
setlocal enabledelayedexpansion
for %%A in (*.cr2 *.jpg) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1,2* delims=-" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
In the loop for /f"tokens=1,2* delims=-" %%D in ..., the first token is assigned to %%D, the second one to %%E and the rest (*) to %%F (but which you do not use), so you should do set folname=%%D-%%E to get the desired folder name in variable folname:
#echo off
setlocal EnableDelayedExpansion
for %%A in ("*-*-*.cr2" "*-*-*.jpg") do (
echo file found %%A
for /f "tokens=1,2 delims=-" %%D in ("%%~nA") do set "folname=%%D-%%E"
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%~A" "!folname!"
)
endlocal
echo Finished
The loops for /f "delims=" %%B and for /f "delims=" %%C are useless, you could use %%~nA and %%~xA directly to get the values fname and fextn, respectively. But you do not need these interim variables at all, therefore I removed them.
And you should use the quoted set syntax like set "folname=%%D-%%E" in general.
I also changed the file masks to not match files that contain less than two hyphens (-).
Actually you do not even need the interim variable folname when you use the tokens %%D and %%E immediately. So you do no longer need delayed expansion any more:
#echo off
setlocal
for %%A in ("*-*-*.cr2" "*-*-*.jpg") do (
echo file found %%A
for /f "tokens=1,2 delims=-" %%D in ("%%~nA") do (
echo folder name %%D-%%E
if not exist "%%D-%%E" (
echo Folder %%D-%%E does not exist, creating
md "%%D-%%E"
) else (
echo Folder %%D-%%E exists
)
echo Moving file %%A to folder %%D-%%E
move "%%~A" "%%D-%%E"
)
)
endlocal
echo Finished
Related
I have files in one folder with the names like
John-Smith-014_15616812_5165
Robert-Walker-014_15644812_5145
I want these files to be checked and if they matched to the already existed one then automatically moved there.
Destination folders are already created and they look like:
John-Smith-156.81.251.452
Robert-Walker-12.108.36.5418
I have tried this code:
#echo off
setlocal EnableDelayedExpansion
pushd "C:\dest"
FOR %%G IN (*) DO (
FOR /F "tokens=1 delims=_" %%a IN ("%%G") do (
set "outFolder=%%a"
for /D %%i in (*.*) do (
for /F "tokens=1 delims=_" %%b IN ("%%i") do (
if "%%a"=="%%b" set "outFolder=%%i"
)
)
if not exist "!outfolder!" md "!outfolder!"
move "%%G" "!outfolder!"
)
)
popd
pause
This code partly works but it can't make difference between Robert-Walker to Robert-Brown and it will move both of them to the folder with the name Robert-Walker-12.108.36.5418
In this code it won't check both first and second tokens in order to sort those files according to their name and surname, instead it sorts only by their name.
I am trying to move a list of .pdf files to folders based on the first 4 characters of said pdf files
#echo off
setlocal enabledelayedexpansion
for %%A in (*.pdf) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1* delims=_" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
pause
To move all .pdf files in the current directory into directories named using the first four characters of their basename, here's a batch-file example, (without all of the unnecessary screen output):
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For %%A In (*.pdf)Do (Set "fN=%%~nA"
SetLocal EnableDelayedExpansion
RoboCopy . "!fN:~,4!" "%%A" /Mov>NUL
EndLocal)
EndLocal
GoTo :EOF
You could probably even do it as a single line command.
From a batch-file:
#For %%A In (*.pdf)Do #Set "fN=%%~nA"&Call RoboCopy . "%%fN:~,4%%" "%%A" /Mov>NUL
From a single cmd instance:
For %A In (*.pdf)Do #Set "fN=%~nA"&Call RoboCopy . "%fN:~,4%" "%A" /Mov>NUL
Please note that the ideas presented above assume that your .pdf basenames do not contain any exclamation marks/points and that Robocopy.exe exists in the current directory or within the locations specified under %PATH%.
Please also note that the 4th character in your basenames should not be a space or period, as the Windows shell and user interface does not support those.
I want to fetch two sub string from my file name in order to create Folder String.
My file name is "SM-SM-ABC_ab12 cd34_AA 11_abc123.txt"
here "ab12 cd34" is 1st folder and "AA 11" is 2nd folder
I have written a code but After adding #Compo code I ma not able to move file to directory. I want to move multiple files to respective folders.
Can some one help whats wrong?
#Echo Off
set Path1= d:\A
:: SDate=DAYMONTHYEAR FORMAT of Systemdate
echo %Path1%
set SDate=%date:~7,2%%date:~4,2%%date:~10,4%
echo %SDate%
::Variable for folder path
Pushd %Path1%
for %%i in (*.*) do SET "FPath=%%~ni"
For /F "Tokens=2-3 Delims=_" %%A In ("%FPath%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
if not exist "%Path1%\%FoldOne%\%FoldOne%\%SDate%" (
mkdir "%Path1%\%FoldOne%\%FoldOne%\%SDate%" )
move %Path1%\* "%Path1%\%FoldOne%\%FoldTwo%\%SDate%\"
echo test %Path1%
echo test %FPath%
)
GoTo :EOF
Is this what you are trying to achieve?
#Echo Off
Set "FPath=SM-SM-ABC_ab12cd34_AA11_abc123.txt"
For /F "Tokens=2-3 Delims=_" %%A In ("%FPath%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B")
Echo(%%FoldOne%%=%FoldOne%
Echo(%%FoldTwo%%=%FoldTwo%
Timeout -1
GoTo :EOF
[Edit /]The following code may provide you with a solution for your updated requirements:
#Echo Off
Set "Path1=D:\A"
If /I Not "%CD%"=="%Path1%" Pushd "%Path1%" 2>Nul || Exit/B
For /F "EOL=L" %%A In ('WMIC OS GET LocalDateTime') Do For %%B In (%%~nA
) Do Set "SDate=%%B"
Set "SDate=%SDate:~6,2%%SDate:~4,2%%SDate:~,4%"
For %%A In ("*_*_*_*.*") Do Call :Sub "%%A"
Timeout -1
GoTo :EOF
:Sub
For /F "Tokens=2-3 Delims=_" %%A In (%1) Do If Not "%%A"=="" If Not "%%B"=="" (
If Not Exist "%%A\%%B\%SDate%\" MD "%%A\%%B\%SDate%"
Move %1 "%%A\%%B\%SDate%")
Hello i have a batch script but i cant work out how to change the path to scan all subfolders within the directory.
In other words i dont want -
C:\Users\ally\Desktop\Documents\Table\CSV versions\2014\
but rather:
C:\Users\ally\Desktop\Documents\Table\CSV versions
as there are lots of different years of data in seperate folders.
Also to note within year folder there are month folders and within that there are the csv files.
#echo off
setlocal enabledelayedexpansion
set "target=C:\Users\ally\Desktop\Documents\All"
cd /d "C:\Users\ally\Desktop\Documents\Table\CSV versions\2014\"
for /L %%a in (101,1,148) do (
set num=%%a
del "%target%\-!num:~-2!.csv" 2>nul
>"%target%\-!num:~-2!.csv.txt" echo Type,angle,edge,Date,Frame,Sum,Mafe,Comp,Rim,Dose,Ell,Role
)
for %%a in (*.csv) do (
for /f "skip=1 usebackq delims=" %%b in ("%%a") do (
for /f "tokens=1,2 delims=-," %%c in ("%%b") do (
set "line=%%c"
if /i "!line:~0,2!"=="HH" >> "%target%\-%%d.csv.txt" echo %%b
)
)
)
ren "%target%\*.csv.txt" *.
pause
To process every folder under the All tree then you can use a for /d /r loop and pushd/popd to set the current folder.
This assumes that every folder has the files you want to process.
Test this on a copy of your data and change the folder to point to it.
You seem to be deleting .csv files, creating .csv.txt files and then trying to process *.csv in the lower loop. Should that be *.csv.txt ?
#echo off
setlocal enabledelayedexpansion
for /d /r "c:\Users\ally\Desktop\Documents\All" %%z in (*) do (
pushd "%%z"
for /L %%a in (101,1,148) do (
set num=%%a
del "-!num:~-2!.csv" 2>nul
>"-!num:~-2!.csv.txt" echo Type,angle,edge,Date,Frame,Sum,Mafe,Comp,Rim,Dose,Ell,Role
)
for %%a in (*.csv) do (
for /f "skip=1 usebackq delims=" %%b in ("%%a") do (
for /f "tokens=1,2 delims=-," %%c in ("%%b") do (
set "line=%%c"
if /i "!line:~0,2!"=="HH" >> "-%%d.csv.txt" echo %%b
)
)
)
ren "*.csv.txt" *.
popd
)
pause
Try adding another loop that will walk down the directory tree and if it finds a csv file, it will process it:
#echo off
setlocal enabledelayedexpansion
set "target=C:\Users\ally\Desktop\Documents\All"
for /f "tokens=1* delims=" %%D in ('dir /s /b /o:-n /a:d "C:\Users\ally\Desktop\Documents\Table\CSV versions"') do (
cd /d "%%~fD"
if exist *.csv (
for /L %%a in (101,1,148) do (
set num=%%a
del "%target%\-!num:~-2!.csv" 2>nul
>"%target%\-!num:~-2!.csv.txt" echo Type,angle,edge,Date,Frame,Sum,Mafe,Comp,Rim,Dose,Ell,Role
)
for %%a in (*.csv) do (
for /f "skip=1 usebackq delims=" %%b in ("%%a") do (
for /f "tokens=1,2 delims=-," %%c in ("%%b") do (
set "line=%%c"
if /i "!line:~0,2!"=="HH" >> "%target%\-%%d.csv.txt" echo %%b
)
)
)
ren "%target%\*.csv.txt" *.
)
)
pause
Explanation of the dir switches:
/s - Displays files in specified directory and all subdirectories.
/b - Uses bare format (no heading information or summary).
/o:in - Lists the files in reverse order
/a:d - Displays only folders
Explanation of the %%~fD: expands %A to a fully qualified path name (from for /?)
I searched extensively and found what I believe to be a solution to my problem, which is merging CSV files without duplicating headers each time. It looks like it works, except it's only copying the first file in the folder into the destination file. I think it's unable to open the files because they have a space in the name. I've been advised I probably just need to put quotes somewhere, but I'm not sure where they would go. Thanks in advance.
#ECHO OFF
SET first=y
SET newfile=new.csv
for %%F in (*.csv) do IF NOT %%F==%newfile% (
if defined first (
COPY /y "%%F" %newfile% >nul
set "first="
) else (
FOR /f "skip=1delims=" %%i IN (%%F) DO >> %newfile% ECHO %%i
)
)
#echo off
setlocal enableextensions disabledelayedexpansion
rem configure paths
set "source=*.csv"
set "target=newfile.csv"
rem remove output file if needed
if exist "%target%" del "%target%" >nul 2>nul
rem search for header row
set "headerRow="
for %%f in ("%source%") do (
<"%%~ff" ( for /l %%a in (1 1 10) do if not defined headerRow set /p "headerRow=" )
if defined headerRow goto haveHeader
)
:haveHeader
if not defined headerRow (
echo ERROR: impossible to get header row.
goto endProcess
)
rem output header to header file to use as filter.
rem header is cut to avoid findstr limitations on search strings
set "headerFile=%temp%\%~nx0_headerFile.tmp"
setlocal enableextensions enabledelayedexpansion
> "%headerFile%" echo(!headerRow:~0,125!
endlocal
rem search for input files with matching headers to join to final file
for /f "tokens=*" %%f in ('findstr /m /b /l /g:"%headerFile%" "%source%"') do (
if not exist "%target%" (
rem first file is directly copied
copy "%%~f" "%target%" /y > nul 2>nul
) else (
rem next files are filtered to exclude the header row
findstr /v /b /l /g:"%headerFile%" "%%~f" >> "%target%"
)
echo ... [%%~ff] joined to %target%
)
rem remove the temporary header file
del "%headerFile%" >nul 2>nul
:endProcess
endlocal
Here's another option.
#echo off
set "newfile=new.txt"
del "%newfile%" 2>nul
for %%a in (*.csv) do (
if not exist "%newfile%" (type "%%a" > "%newfile%") else (more +1 "%%a" >> "%newfile%")
)
ren "%newfile%" "new.csv"
#echo off &setlocal disableDelayedExpansion
set "NewFile=new.csv"
>"%NewFile%" cd .
for /f "tokens=1*delims=:" %%a in ('dir /b /a-d /od *.csv ^|findstr /nvx "%NewFile%"') do (
if %%a equ 1 (
copy /b "%%~b" "%NewFile%" >nul
) else (
for /f "skip=1delims=" %%c in ('type "%%~b"') do >>"%NewFile%" echo(%%c
)
)
sed for Windows
I think the line near the end starting "FOR /f" is mixed up and it should be:
#ECHO OFF
SET first=y
SET newfile=new.csv
for %%F in (*.csv) do IF NOT %%F==%newfile% (
if "%first%"=="y" (
COPY /y "%%F" %newfile% >nul
set "first="
) else (
FOR /f "skip=1delims=" %%i IN ("%%F") DO ECHO %%i >> %newfile%
)
)
#ECHO OFF
SET first=y
SET "newfile=new.txt"
del new.csv 2>nul >nul
for %%F in (*.csv) do (
if defined first (
COPY /y "%%F" %newfile% >nul
set "first="
) else (
FOR /f "usebackqskip=1delims=" %%i IN ("%%F") DO >> %newfile% ECHO %%i
)
)
ren %newfile% new.csv
The set "var=value" syntax ensures that any trailing spaces on the batch line are not included in the value assigned to var.
First step is to delete the new.csv file - the 2>nul >nul redirects messages and error messages from del so that the command is totally silent - whether the file exists or not.
Next, you don't need to check whether the new.csv is selected as %%F because it's just been deleed if it did exist, and the output is now to new.txt (filename not critical - actually, I'd be tempted to call it new.vsc. The critical thing is that it isn't .csv so for doesn't need to check it)
Other than the first file (a copy is faster than reading and echoing), the name of the file (in %%F) being read into %%i, since it needs to be "quoted" (to tell CMD that the spaces are not separators) you need to add the usebackq to the for/f controls.
Finally, rename your file to the desired new name.
This should fix the problem.