I have 2 bat files working perfectly for my data. One to copy and move some files. The other to group files based on a pattern in their names. I need to combine both in a file or I need to make them work with running one command.
bat 1:
#echo off
setlocal enabledelayedexpansion
rem set language pre-requisites
rem purpose can be 'test' or 'deploy'
SET "purpose=test"
SET "language=English-Indian"
SET "lang_code=EnIn"
rem Since we have only 2 options test or deploy
if "%purpose%"=="test" (
SET "folder=%lang_code%P101M2Tsub"
)
if "%purpose%"=="deploy" (
SET "folder=%lang_code%P101M2DFull"
)
rem set required paths here. Don't edit unless necessary
SET Source101="D:\..path..\*.wav"
SET SourceLive="D:\..path..\M2"
SET Destination="D:\..path..\M3\*"
rem copying the data
xcopy %SourceLive% %Destination% /e /i /h
rem copying 101 files into the other 100 folders
for /d %%a in (%Destination%) do copy %Source101% "%%a"
rem renaming M3 folders
cd %Destination%
for /d %%a in (*) do (
set "p=%%a"
set "fp=!p:~0,8!" & set "tp=!p:~10!"
ren %%a !fp!M3!tp!
)
bat 2:
#echo off
rem Prepare environment
setlocal enableextensions disabledelayedexpansion
rem configure where to start
set "root=some path"
rem For each file under root that match indicated pattern
for /r "%root%" %%f in (*_*_*.wav) do (
rem Split the file name in tokens using the underscore as delimiter
for /f "tokens=2 delims=_" %%p in ("%%~nf") do (
rem Test if the file is in the correct place
for %%d in ("%%~dpf.") do if /i not "%%~p"=="%%~nd" (
rem if it is not, move it where it should be
if not exist "%%~dpf\%%~p" md "%%~dpf\%%~p"
move "%%~ff" "%%~dpf\%%~p"
)
)
)
I need to combine these two bat files into one. As in I need one working bat file. Can someone help?
One simple solution
setlocal enabledelayedexpansion
....
the work in batch file 1
....
setlocal disabledelayedexpansion
the work in batch file 2
....
endlocal
endlocal
Anyway, the only reason for the disabledelayedexpansion in second batch file is to avoid problems with special characters in file/folder names. First batch file doesn't care of it so, if it work, remove the disabledelayedexpansion from second batch file.
Could be as simple as
call batch1
call batch2
BUT
perhaps the cd before the final for in batch1 is changing to a directory that batch2 does not expect.
if so, change the cd to a pushd and add a popd after the current last line of batch1.
OR
since the only part of batch1 that appears to REQUIRE delayedexpansion is the final FOR loop, change batch1 to disabledelayedexpansion mode, then add
setlocal enabledelayedexpansion
directly before the final for loop and
endlocal
on the next line after the final close-parenthesis.
Related
I would like to append recursively folder (and parent folder) names to each *.txt files that folder contains. After that I want to move all files to base folder and delete all folders. I need to achieve this in Windows BATCH script. For examle:
\BaseFolder\A01\B01\EX1.TXT
\BaseFolder\C01\EX2.TXT
\BaseFolder\EX3.TXT
To:
\BaseFolder\A01-B01-EX1.TXT
\BaseFolder\C01-EX2.TXT
\BaseFolder\EX3.TXT
To do this i've found this solution thanks to JosefZ:
Recursively append folder name to the files in Windows batch file
#echo OFF
SETLOCAL EnableExtensions
for /F "delims=" %%G in ('dir /B /S "C:\Source\*.txt"') do (
for %%g in ("%%~dpG.") do rename "%%~fG" "%%~nxg_%%~nxG"
)
pause
where the FOR loops are:
outer %%G loop creates a static list of .txt files (recursively), and
inner %%g loop gets the parent folder of every particular file.
But this solve only a part of my goal. Can anyone help?
Here's a 'fun' idea:
#Set "BaseFolder=C:\Users\Mustafa\BaseFolder"
#ForFiles /P "%BaseFolder%" /S /M *.txt /C "Cmd /C If #IsDir==FALSE For /F 0x22Tokens=*Delims=.\0x22 %%# In (#RelPath)Do #If Not 0x22%%#0x22==#File Set 0x22_=%%#0x22&Call Move /Y 0x22%BaseFolder%\%%#0x22 0x22%BaseFolder%\%%_:\=-%%0x22>NUL"
Please note that this untested solution is very likely to have command line length limitations. I would therefore avoid it if your initial base folder is deep within the volume and/or its tree is deep or carries long file and directory names. Given that cautionary information, please remember to adjust the full path value on line one as necessary.
The following script should accomplish what you want, namely moving and renaming the files as predefined and deleting the remaining empty sub-directories (see all the explanatory rem remarks):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=.\BaseFolder" & rem // (target base directory)
set "_MASK=*.txt" & rem // (file search pattern)
set "_CHAR=-" & rem // (separator character)
rem // Switch to target directory:
pushd "%_ROOT%" && (
rem // Loop through list of relative paths of matching files:
for /F "tokens=1* delims=:" %%E in ('
xcopy /L /S /I "%_MASK%" "%TEMP%" ^| find ":"
') do (
rem // Store current relative file path, initialise variables:
set "FILE=%%F" & set "NAME=" & set /A "NUM=0"
rem // Toggle delayed expansion to avoid trouble with `!` and `^`:
setlocal EnableDelayedExpansion
rem // Loop through all individual elements of file relative path:
for %%I in ("!FILE:\=" "!") do (
endlocal
rem // Store current path element and count them:
set "ITEM=%%~I" & set /A "NUM+=1"
setlocal EnableDelayedExpansion
rem // Build new file name and pass it over `endlocal` barrier:
for /F "delims=" %%N in ("!NAME!%_CHAR%!ITEM!") do (
endlocal
set "NAME=%%N"
setlocal EnableDelayedExpansion
)
)
rem // Finalise new file name:
if defined _CHAR set "NAME=!NAME:*%_CHAR%=!"
rem // Actually move and rename the current file:
> nul move "!FILE!" "!NAME!"
rem // Switch to parent directory of current file:
pushd "!FILE!\.." && (
rem // Loop through parent directory elements:
for /L %%N in (2,1,!NUM!) do (
rem // Try to remove parent directory when empty, go one up:
set "DD=!CD!" & cd ".." & 2> nul rd "!DD!"
)
rem // Return to previous working directory:
popd
)
endlocal
)
rem // return to original working directory:
popd
)
endlocal
exit /B
I have files named as RabcdYYMMKKACCOUNT.TXT in the Subfolders of a folder where YYMM is year, month this will change. KK is another identifier, I want all the files to be renamed to MSFKKDNB.ABC, the KK is the identifier in the input file.
Below is the one i tried and the result of it:
FOR /R %%f IN (*account.txt) DO REN "%%f" *dnb.abc
R00531706AUAccount.txt is renamed to R00531706AUAccount.txtdnb.abc
but the output should be MSFAUDNB.abc
This could be done for example with:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for /R %%I in (???????????account.txt) do (
set "FileName=%%~nI"
set "NewFileName=MSF!FileName:~9,2!DNB.abc"
if not exist "%%~dpI!NewFileName!" (
ren "%%~fI" "!NewFileName!" 2>nul
if not exist "%%~dpI!NewFileName!" echo Failed to rename file: "%%~fI"
) else (
echo Cannot rename file: "%%~fI"
)
)
endlocal
The file name of found account text file is assigned to environment variable FileName.
The new name for the file is created by concatenating the fixed parts MSF and DNB.abc with the 2 characters to keep from file name using string substitution and delayed expansion.
Next it is checked if a file with new name does not already exist. Is this the case the file renaming is done otherwise an error message is output.
After renaming the file it is checked if that was successful. A slightly different error is output if renaming failed for example because of a sharing violation.
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 /?
for /?
if /?
ren /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators.
Try this:
#Echo Off
For %%A In ("*account.txt") Do (Set "_=%%~nA"
SetLocal EnableDelayedExpansion
Ren "%%A" "MSF!_:~-9,2!DNB.abc"
EndLocal)
I would probably do it the following way, provided that the files to rename are located in immediate sub-directories (YYMM) of the given root directory and nowhere else:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "_ROOT=." & rem // (specify path to the root directory)
for /D %%D in ("%_ROOT%\????") do (
for %%F in ("%_ROOT%\%%~nxD\R??????????Account.txt") do (
set "FDIR=%%~nxD" & set "FILE=%%~nxF"
setlocal EnableDelayedExpansion
ECHO ren "!_ROOT!\!FDIR!\!FILE!" "MSF!FILE:~9,2!DNB.abc"
endlocal
)
)
endlocal
exit /B
If you want to check whether both the sub-directory name and the year/month portion of the file names are purely numeric, you could use the following script:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "_ROOT=." & rem // (specify path to the root directory)
for /F "delims= eol=|" %%D in ('
dir /B /A:D "%_ROOT%\????" ^| ^
findstr "^[0123456789][0123456789][0123456789][0123456789]$"
') do (
for /F "delims= eol=|" %%F in ('
dir /B /A:-D "%_ROOT%\%%~nxD\R??????????Account.txt" ^| ^
findstr "^R....[0123456789][0123456789][0123456789][0123456789].."
') do (
set "FDIR=%%~nxD" & set "FILE=%%~nxF"
setlocal EnableDelayedExpansion
ECHO ren "!_ROOT!\!FDIR!\!FILE!" "MSF!FILE:~9,2!DNB.abc"
endlocal
)
)
endlocal
exit /B
If you want to check whether the sub-directory name matches the year/month (YYMM) portion of the file names, replace the pattern R??????????Account.txt by R????%%~nxD??Account.txt (for both scripts).
After having verified the correct output of either script, remove the upper-case ECHO commands to actually rename any files!
Basically, both scripts use sub-string expansion to extract the identifier part (KK) from the file names. Since there are variables set and read in the same block of code, delayed expansion is required for that. The second approach does not list the sub-directories and files by standard for loops, it uses the dir command, findstr to filter their names and a for /F loop to capture the resulting output for both sub-directories and files.
I am trying to have a batch file output ONLY the short-name of folders and sub-folders to a file. However, with the example below I am only able to get the fullpath.
DIR /S /B /O:N /A:D > FolderList.txt
Which will output:
X:\Example\Folder 1
X:\Example\Folder 2
X:\Example\Folder 3
X:\Example\Folder 1\Sub-Folder 1
X:\Example\Folder 1\Sub-Folder 2
X:\Example\Folder 2\Sub-Folder 1
When the desired output is:
Folder 1
Folder 2
Folder 3
Folder 1\Sub-Folder 1
Folder 1\Sub-Folder 2
Folder 2\Sub-Folder 1
The issue comes with the /S switch that allows the DIR command to recurse into sub-folders.
Is there a simple way, using only a Windows Batch File, to output a list of folders and sub-folders in the current directory to a text file?
#ECHO OFF
FOR /f "delims=" %%a IN ('DIR /S /B /O:N /A:D') DO (
SET "name=%%a"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO(!name:%cd%\=!
endlocal
)
GOTO :EOF
made a little more confusing because you ask for the "short name" then describe the "relative name".
Obviously, name simply echoed to screen. You're aware of how to redirect.
Just to include a solution using a recursive function call approach
#echo off
setlocal enableextensions disabledelayedexpansion
call :getSubFolderList "%~1"
goto :eof
:getSubFolderList folder [prefix]
for /d %%a in ("%~f1.\*") do for %%b in ("%~2%%~nxa") do (
echo %%~b
call :getSubFolderList "%%~fa" "%%~b\"
)
goto :eof
When called with a starting folder, it will iterate over the list of subfolders, and for each one the subroutine will call itself to handle the descending folders.
The other answers to this question using echo to output the folder path use delayedexpansion, echoing the content of the variable used without any problem caused by the parser. But the code in this answer does not use delayed expansion, and characters as &() in the folder names can be a problem in the echo command.
To avoid this problem, the value to echo is quoted and wrapped inside a for replaceable parameter. That is the reason for the for %%b in the code.
To generate a file with the list of folders, the only change needed is, in the first call command:
call :getSubFolderList "%~1" > fileList.txt
note: the code in the answer has been written to receive the folder to be processed as the first argument to the batch file. Change "%~1" to your needs.
This uses a little trick with the old SUBST command to make the root folder a drive letter. Then you can use the FOR command modifiers to drop the drive letter from the variable on output.
#echo off
SET "folders=X:\Example"
subst B: "%folders%"
B:
(FOR /F "delims=" %%G in ('DIR /S /B /O:N /A:D') do echo %%~pnxG)>"%~dp0folderlist.txt
subst B: /D
Now obviously this does not check to make sure that the drive letter B: is available before using it. Easy enough to add some code to check for a drive letter that is not in use before executing the SUBST command.
To confirm my comment with regard the duplicate response:
#Echo Off
SetLocal EnableDelayedExpansion
For /L %%A In (1 1 8192) Do If "!__CD__:~%%A,1!" NEq "" Set/A "Len=%%A+1"
SetLocal DisableDelayedExpansion
(For /D /R %%A In (*) Do (
Set "AbsPath=%%A"
SetLocal EnableDelayedExpansion
Echo(!AbsPath:~%Len%!
EndLocal))>FolderList.txt
Is it posible to copy and make directories automatically from file name substrings using Robocopy?
I mean i have files like these. LAJ00306130201004626.rc the first 8 chararacters are control number (LAJ00306=control number) this would be the name of the folder and the rest are the date and time (Date=130201) (time=004626).
LAJ00306130201004626.rc
LAJ00306130202004626.rc
LAJ00306130203004626.rc
LAJ00307130201004626.rc
LAJ00307130202004626.rc
and i would like to copy and create folders from the file name like under and copy the files mentioned before in the new folders.
LAJ00306
LAJ00307
I hope to be clear if necessary ask me for more information
try this, look at the output and remove the echos before MD and ROBOCOPY, if it looks good:
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcefolder=."
SET "targetfolder=X:\data"
CD /d "%sourcefolder%"
FOR %%a IN (*.rc) DO (
SET "fname=%%a"
SET "folder=!fname:~0,8!"
SET "$!folder!=1"
)
FOR /f "delims=$=" %%a IN ('set "$"') DO (
ECHO MD "%targetfolder%\%%a" 2>nul
ECHO ROBOCOPY "%sourcefolder%" "%targetfolder%\%%a" "%%a*.rc"
)
Set sourcefolder and targetfolder for your folder tree.
Try this:
#echo off
pushd "c:\source folder"
setlocal enabledelayedexpansion
for %%a in (*.rc) do (
set "name=%%a"
robocopy "%cd%" "%%a" "D:\target directory\!name:~0,8!"
)
popd
Answers to your questions are:
pushd "drive:\path" makes the location the current working directory.
popd restores the last working directory
setlocal enabledelayedexpansion allows you to change and use variables within a loop, using the !variable! syntax.
If your 2000 files are in a single folder then it should work - but test it on some sample files first so that you can see how it will work.
#ECHO OFF
SETLOCAL
SET "sourcedir=."
SET "destdir=c:\destdir"
FOR /f "tokens=1*delims=_" %%i IN (
'dir /b /a-d "%sourcedir%\*_*."'
) DO XCOPY /b "%sourcedir%\%%i_%%j" "%destdir%\%%i\"
GOTO :EOF
This should accomplish the task described. You'd need to set up the source and destination directories to suit, of course. Add >nul to the end of the XCOPY line to suppress 'copied' messages.
I have a directory full with time stamped webcamfiles. It start at midnight, and take a picture every minute.
0001webcamimage.jpg
0002webcamimage.jpg
0003webcamimage.jpg
...
0059webcamimage.jpg
0100webcamimage.jpg
Now i want to convert all the files with a batch-file to this format. The sequence is important.
0001.jpg
0002.jpg
0003.jpg
...
0060.jpg
0061.jpg
Can someone help me?
Assuming Windows & 4 digit prefixes
setlocal enabledelayedexpansion
for %%f in (*webcamimage.jpg) do (
set name=%%f
ren "!name!" "!name:~0,4!.jpg"
)
The following is similar to #Alex K.'s suggestion but doesn't extract numbers from the original names. Instead, it uses a counter and forms the new names using the counter's values:
#ECHO OFF
SET /A num=10000
FOR %%I IN (*webcamimage.jpg) DO (
SET /A num+=1
SETLOCAL EnableDelayedExpansion
RENAME "%%I" !num:~-4!.*
ENDLOCAL
)
Note that the new names will always start with 0001.jpg.
UPDATE
If the batch file is not in the same directory as the images, you can specify the path to them like this:
#ECHO OFF
SET /A num=10000
FOR %%I IN (D:\path\to\images\*webcamimage.jpg) DO (
SET /A num+=1
SETLOCAL EnableDelayedExpansion
RENAME "%%I" !num:~-4!.*
ENDLOCAL
)
Alternatively, you could add the CD /D command before the loop to change to the directory where the images are:
#ECHO OFF
CD /D D:\path\to\images
SET /A num=10000
FOR %%I IN (*webcamimage.jpg) DO (
SET /A num+=1
SETLOCAL EnableDelayedExpansion
RENAME "%%I" !num:~-4!.*
ENDLOCAL
)
If, after finishing the job, you need to change back to the directory that was active before invocation of the batch file, use PUSHD and POPD:
#ECHO OFF
PUSHD D:\path\to\images
SET /A num=10000
FOR %%I IN (*webcamimage.jpg) DO (
SET /A num+=1
SETLOCAL EnableDelayedExpansion
RENAME "%%I" !num:~-4!.*
ENDLOCAL
)
POPD
And, of course, you can parametrise the path as well so that you can specify it in the command line when invoking the batch file. Here's how:
#ECHO OFF
SET "imagepath=%~1"
SET /A num=10000
FOR %%I IN ("%imagepath%\*webcamimage.jpg") DO (
SET /A num+=1
SETLOCAL EnableDelayedExpansion
RENAME "%%I" !num:~-4!.*
ENDLOCAL
)
Now you can invoke the batch file at the command prompt or from another batch file like this:
batchname.bat D:\path\to\images
(In case you are not aware: if you call a batch file from another batch file, you'll likely need to add CALL before the name of the batch file being called, i.e. CALL batchname parameters.)
With linux, use rename :
rename 'webcamimage' '' *.jpg