I would like to rename files that are uploaded to another server from extension .txt to .txt_mvd and move to a different directory for archiving in a Windows batch mode. Can anyone help with what the windows batch script should be?
Thanks.
Here is the code
FOR /R C:\your_folder %%d IN (*.txt) DO (
ren %%d %%~nd.txt_mvd
)
%%d is the full file name + path
%%~nd return only the file name without the extension
Using the /R parameter, it will scan folder and subfolder
UPDATE 1
The following code should work as required.
I've added an IF that ignore the subfolders.
FOR /R E:\your_folder\ %%d IN (*.*) DO (
IF %%~dpd==E:\your_folder\ (
ren %%d %%~nd.txt_mvd
)
)
UPDATE 2
Fixed code
FOR /R E:\your_folder\ %%d IN (*.txt) DO (
IF %%~dpd==E:\your_folder\ (
ren %%d %%~nd.txt_mvd
)
)
UPDATE 3
Here is a more generalized and parametrized version of the script.
Change the starting parameter to your need (the first 4 lines of code).
This script first rename the files you choose (1st parameter) in your starting folder (3rd parameter), change the extension to the new one (2nd parameter), and then move the renamed files in the folder of your choice (4th parameter).
set Extension_of_file_you_want_to_renamne_and_move=txt
set New_extension_of_moved_files=txt_mvd
set Folder_that_contain_your_files=C:\Your_starting_folder\
set Folder_where_to_move_your_files=C:\Your_destnation_folder\
FOR /R %Folder_that_contain_your_files% %%d IN (*.%Extension_of_file_you_want_to_renamne_and_move%) DO (
IF %%~dpd==%Folder_that_contain_your_files% (
IF %%~xd==.%Extension_of_file_you_want_to_renamne_and_move% (
ren "%%~d" "%%~nd.%New_extension_of_moved_files%"
move "%%~dpnd.%New_extension_of_moved_files%" "%Folder_where_to_move_your_files%"
)
)
)
when you change the parameter DON'T add any space.
So DON'T change the parameter like that:
set Folder_that_contain_your_files = c:\myFolder <--- WRONG, WON'T WORK, there are unneeded space
instead, write the parameter WITHOUT unneeded space:
set Folder_that_contain_your_files=c:\myFolder <--- OK, THIS WILL WORK, there are no extra spaces
UPDATE 4
Fixed the code, I've added some quotation marks, without them the code wont works if folder name contained spaces.
set Extension_of_file_you_want_to_renamne_and_move=txt
set New_extension_of_moved_files=txt_mvd
set Folder_that_contain_your_files=C:\Your_starting_folder\
set Folder_where_to_move_your_files=C:\Your_destnation_folder\
FOR /R "%Folder_that_contain_your_files%" %%d IN (*.%Extension_of_file_you_want_to_renamne_and_move%) DO (
IF "%%~dpd"=="%Folder_that_contain_your_files%" (
IF %%~xd==.%Extension_of_file_you_want_to_renamne_and_move% (
ren "%%~d" "%%~nd.%New_extension_of_moved_files%"
move "%%~dpnd.%New_extension_of_moved_files%" "%Folder_where_to_move_your_files%"
)
)
)
Related
I've written a simple batch file to move .pdf files to certain folders located on a file system. Currently, the code checks to see if a folder with a company's name exists (P:\invoices\%company%). If the folder exists then the code checks to see if a subfolder called 2021 is located at P:\invoices\%company%\2021. If the 2021 folder already exists, the code moves the .pdf file to that 2021 folder.
However, if the 2021 subfolder does not exist, then the code is supposed to create a 2021 folder at P:\invoices\%company%\2021. I used the md command to do this but it creates a generic file called 2021 instead of a folder. Then the .pdf file disappears into thin air, presumably because it is moving it into a file instead of a folder.
Here is the code:
#echo off
for /r "C:\Users\me\Scan\*.pdf" %%G in (*.pdf) do set "name=%%~nG"
for /f "tokens=1-2 delims=-" %%i in ("%name%") do set "company=%%i"
if exist "P:\invoices\%company%" do (
if exist "P:\invoices\%company%\2021" do (
move /y "C:\Users\me\Scan\*.pdf" "P:\invoices\%company%\2021"
)
else do (
md "P:\invoices%\company%\2021"
move /y "C:\Users\me\Scan\*.pdf" "P:\invoices%\company%\2021"
)
)
What am I doing wrong?
#echo off
:: This ensures that the original environment is restored on termination
SETLOCAL
:: Use variable so year needs to be changed in only 1 place
set "year=2021"
:: And representing destination parent-directory
set "destparent=P:\invoices"
:: read the filenames from the tree
for /r "C:\Users\me\Scan\*.pdf" %%G in (*.pdf) do (
REM %%G has full filename, %%~nG the name part only
for /f "tokens=1 delims=-" %%i in ("%%~nG") do (
REM %%i has company name
REM Optional to auto-create company-directory begin
REM force Company directory to exist
MD "%destparent%\%%i" 2>nul >nul
REM Optional to auto-create company-directory end
REM If company directory truly exists
if exist "%destparent%\%%i\." (
rem force year subdirectory to exist
MD "%destparent%\%%i\%year%" 2>nul >nul
rem does subdirectory now exist?
if exist "%destparent%\%%i\%year%\." (
move /y "%%G" "%destparent%\%%i\%year%\"
) else (
echo "%destparent%\%%i\%year%" directory not found
)
) else (
echo "%destparent%\%%i" directory not found
)
)
)
[Untested - apply to dummy directories for verification]
OP code problems:
The for /r ... %%G will assign to name the name of the LAST file encountered, which will be the from the very last directory in the subtree that contains a file passing the name-mask *.pdf Then the value installed in name is only used to derive the company-name.
company is set up from the part before the first - in name. The part between the first and second - in name (or end of name) is assigned to %%j and never used. OP should consider the possibility that the actual company-name is hyphenated.
OP's code uses if ... DO ( (more than once). DO is illegal here and must be omitted.
OP's code uses else ... DO ( . DO is illegal here and must be omitted. The else keyword must be on the same physical line as the ) for the true code block (parenthesised sequence of statements)
The MOVE statements attempt to move ALL of the .pdf files in the selected subtree-rootdirectory to the destination, regardless of file's company-code or the fact that the selected company-code may be from the .pdf at the deepest level of the tree.
I've attempted to fix the code to do what I suspect the actual intention of the code is, being to move the .pdf files from the subtree to each file's appropriate destination\company\2021 directory, creating directories as necessary.
I will emphasise one again that this code is UNTRIED.
As a suggestion for testing, on a copy of the batch, I would replace each MD and MOVE statement with ECHO MD and ECHO MOVE respectively, and omit all of the redirection statements 2>nul and >nul (which are intended to suppress unwanted messages)
Finally, I'd insert a PAUSE line before the final goto :eof to permit the resultant proposed-list-of-changes from disappearing as I suspect that we may be dealing with a case of Heretical Clickitis.
Here's how I'd suggest you try the task:
As a batch-file:
#For /R "%UserProfile%\Scan" %%G In (*-*.pdf
) Do #For /F "Delims=-" %%i In ("%%~nG"
) Do #%SystemRoot%\System32\Robocopy.exe "%%~dpG." "P:\invoices\%%i\2021" "%%~nxG" /Mov 1>NUL
Or, as a single line entered in cmd:
For /R "%UserProfile%\Scan" %G In (*-*.pdf) Do #For /F "Delims=-" %i In ("%~nG") Do #%SystemRoot%\System32\Robocopy.exe "%~dpG." "P:\invoices\%i\2021" "%~nxG" /Mov 1>NUL
Just change the paths, %UserProfile%\Scan and P:\invoices, as needed.
[Edit /]
If you want you own code fixing, according to the comments I've already made, and to fix your two previously unmentioned typos md "P:\invoices%\company%\2021" and move /y "C:\Users\me\Scan\*.pdf" "P:\invoices%\company%\2021, which should have read md "P:\invoices\%company%\2021" and move /y "C:\Users\me\Scan\*.pdf" "P:\invoices\%company%\2021 respectively. Then this is how I'd suggest you could have fixed it:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /R "C:\Users\me\Scan" %%G In (*.pdf) Do (
Set "name=%%~nG"
SetLocal EnableDelayedExpansion
For /F "Delims=-" %%i In ("!name!") Do (
EndLocal
Set "company=%%i"
)
SetLocal EnableDelayedExpansion
If Exist "P:\invoices\!company!\" (
If Not Exist "P:\invoices\!company!\2021\" (
MD "P:\invoices\!company!\2021"
)
If Exist "P:\invoices\!company!\2021\" (
Move /Y "%%G" "P:\invoices\!company!\2021"
)
EndLocal
)
Pause
Note: As you are both creating and using variables within the same parenthesized code blocks, I have used delayed expansion to ensure that your updated variables are maintained throughout.
Please now compare my upper answer with your fixed version below it, and see why, I offered the much shorter and simpler solution initially.
Long time reader, first time poster - appreciate any help you can give.
Context: I am looking to tidy up a set of property folders. Currently the parent folders are the projects and the properties are sub-folders. If a property is affected by multiple projects it will be duplicated across the project folders. My goal is to flatten the structure so I simply have one folder per property. (eg., copy from E:\TESTING\Project\Property*.* to E:\TESTING\Property*.*) (NOTE: I'm looking to use a Windows batch script as I don't have permissions to load any custom software)
Issue: I need to consolidate files from the duplicate folders into a new location and ensure any duplicate files are kept and renamed with a suffix. There are thousands of folders so I will need a looping script to minimize manual effort.
Attempt: I found a great script in the forums (copied below) that handles the duplicate file renaming really well and sets the source from a *.txt file. I can't figure out how to set the variables so I can have custom/looping target folders. (I'm happy to develop a *.txt file that will show the relevant target folder per source file if I need to)
Hoping it's something simple that I just don't know yet.
#echo off
setlocal
set "source=E:\TESTING\source.txt"
set "target=E:\TESTING\Destination3\"
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"
pause
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" '
) DO (
rem project in %%a
FOR /f "delims=" %%b IN (
'dir /b /ad "%sourcedir%\%%a\*" '
) DO (
rem property in %%b
ECHO Project\Property being processed : %%a\%%b
rem create new? property directory
MD "%destdir%\%%b" 2>NUL
rem for all files in the property directory,
FOR /f "delims=" %%p IN (
'dir /b /a-d "%sourcedir%\%%a\%%b\*" '
) DO (
IF EXIST "%destdir%\%%b\%%p" (
rem existing filename - need to change
SET "notcopied=Y"
FOR /L %%r IN (1,1,99) DO IF DEFINED notcopied IF NOT EXIST "%destdir%\%%b\%%~np(%%r)%%~xp" COPY "%sourcedir%\%%a\%%b\%%p" "%destdir%\%%b\%%~np(%%r)%%~xp" >nul&SET "notcopied="
) ELSE (
COPY "%sourcedir%\%%a\%%b\%%p" "%destdir%\%%b\%%p" >nul
)
)
)
)
GOTO :EOF
Not really sure why you're reading a file to provide your source directory - or is it directories?
Neither am I sure why you appear to be creating the copies in the same parent - Is there some way of distinguishing a property from a project?
Anyhow, the above routine simply assigns each project directoryname in turn to %%a, and then each project subdirectory to %%b. Then read each filename within %%a\%%b to %%p, create the required subdirectory in the destination (2>nul disposes of the duplicate name messages) and see whether the file already exists in the destination.
If it doesn't, copy it as-is. If it does, then try adding (1)... to the name part until the result is not found. The notcopied flag is used as a switch as if defined is interpreted with the current value of the variable, so setting notcopied to empty makes it not defined, so the loop doesn't try to execute the test further.
OK - the limitation is the final value for %%c - the duplicate-filename counter. I set 99 as the maximum. Adjust as required. The smaller the value you use here, the faster (or more accurately, less slow) the routine is.
Found a pyhton solution here, but I need a batch file-based solution.
Have many files:
SSP4325_blah-blah-blah.xml
JKP7645_blah.xml
YTG6457-blah-blah.xml
And folder names that contain a piece of the file name:
RefID - SSP4325, JKP7645, GHT1278, YRR0023
RefID - YTG6457
I'm looking for a batch solution which would read a portion of the file name at the front (before either the first dash or underscore) and then move that file into the folder where the front of the filename exists as part of the folder name.
So in the above examples, the first two files (SSP4325 and JKP7645) were moved into the first folder because it contained it contained that text as part of the folder name.
The third file would be moved into the second folder.
I have hundreds of files and 63 folders. So I'm hoping to be able to automate.
Can't use Powershell or Python due to limitations of the environment. So hoping for a batch file approach.
Thanks. Sean.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*.xml" '
) DO (
FOR /f "tokens=1delims=_-" %%b IN ("%%a") DO (
FOR /f "delims=" %%d IN (
'dir /b /ad "%destdir%\*%%b*" '
) DO (
ECHO(MOVE "%%a" "%destdir%\%%d\"
)
)
)
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances.
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)
After establishing the directories, the outer loop puts the filename in %%a, the next loop gets the first part of that name, up to but not including the first - or _ (the delims specified) into %%b.
The inner loop finds the target directory containng %%b in the destination directory and constructs an appropriate move line.
This solution review the folders just one time and store they in an array, so this method should run faster.
#echo off
setlocal EnableDelayedExpansion
rem Process the folders
set i=0
for /D %%a in (*) do (
rem Store this folder in the next array element
set /A i+=1
set "folder[!i!]=%%a"
rem Separate folder in parts and store the number of the array element in each one
for %%b in (%%a) do set "part[%%b]=!i!"
)
rem Process the files
for %%a in (*.xml) do (
rem Get the first part of name
for /F "delims=-_" %%b in ("%%a") do (
rem If such a folder exists...
if defined part[%%b] (
rem Get the number of the corresponding array element and move the file
for %%n in (!part[%%b]!) do ECHO move "%%a" "!folder[%%n]!"
) else (
echo No folder exists for this file: "%%a"
)
)
)
This method have also several advantages: you may check if a certain folder does not exists, or get the number of files moved to each folder, etc. If you are not interested in these points, just remove the if command and make the code simpler...
An explanation of array management in Batch files is given at this answer.
I'm trying to create a batch script that creates folders based on lines in a text file. I want to be able to automate the "D" function so no typing required.
#echo off
set /P D="Enter Name e.g. ABCD:"
for /F "delims=" %%a in (list.txt) DO (
FOR %%x IN (
"C:\test\%D%\%%a"
"C:\test\%D%\%%a\Folder1"
"C:\test\%D%\%%a\Folder2"
) DO (
MD "%%~x"
)
)
My List file looks like this
JACK-12345
JOHN-12345
I'm wanting to read the first 4 characters of each line and create directories in relevant folders that already exist.
So JACK-12345 will create a folder in C:\test\JACK\JACK-12345 and JOHN will create a folder C:\test\JOHN\JOHN-12345
Any help would be greatly appreciated!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "targetdir=U:\destdir"
for /F "delims=" %%a in (q35285628.txt) DO (
SET "ch4=%%a"
SET "ch4=!ch4:~0,4!"
FOR %%x IN (
"%targetdir%\!ch4!\%%a"
"%targetdir%\!ch4!\%%a\Folder1"
"%targetdir%\!ch4!\%%a\Folder2"
) DO (
ECHO(MD "%%~x"
)
)
GOTO :EOF
You would need to change the setting of targetdir to suit your circumstances.
I used a file named q35285628.txt containing your data for my testing.
The required MD 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. Append 2>nul to suppress error messages (eg. when the directory already exists)
Invoke delayedexpansion to allow substringing of the metavariable %%a Assig the entire string as read to ch4 then select the first 4 characters.
!var! required within the block to access the changing value of the variable at run-time.
For the extended question (unspecified : where "maths" etc fits into the tree - additional, replacement, whatever??
Using the "meat" of the routine:
SET "ch4=%%a"
SET "ch4=!ch4:~0,4!"
SET "folder1=Folder1"
if /i "!ch4:~0,1!"=="m" SET "folder1=Maths"
if /i "!ch4:~0,1!"=="s" SET "folder1=Science"
FOR %%x IN (
"%targetdir%\!ch4!\%%a"
"%targetdir%\!ch4!\%%a\!folder1!"
"%targetdir%\!ch4!\%%a\Folder2"
) DO (
ECHO(MD "%%~x"
)
)
would replace "folder1" from the original scheme with "Maths" if the first character of the line read from the file was "m" (in either case), "Science" if it was "s" and "Folder1" otherwise.
I have been trying to create a script that check file name, if positive, then rename it and move it to a folder in a server, then check for next argument and do the same thing.
The complete idea is that, I have a system that produces CSV files, the name of the file is generated depending of the area, if I am in Nursing, it will generate a file with the word "Nursing" somewhere, so this will help me for scripting purposes to recognise where to put this file using scripts. It will have to read 3 more arguments but I have just mentioned 2 below.
Filename : testing.bat (I am creating a loop)
This is my code so far.
if exist "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Nursing*.csv" (
ren "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Nursing*.csv" names.csv
move /y "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\names.csv" \\10.10.10.10\scenarios\Nursing
)
else if exist "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Midwifery*.csv" (
ren "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*Midwifery*.csv" names.csv
move /y "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\names.csv" \\10.10.10.10\scenarios\Midwifery
)
else (
echo. Not files detected!
)
timeout /t 1
testing.bat
Any help is welcome.
You have a syntax problem : the locations of the else clauses. It MUST be placed (when used) in the same line that the closing parenthesis of the if command. If you place it in the next line, the parser will take it as another command, not the continuation of the previous if
if exist .... (
....
) else if exist .... (
....
) else (
....
)
Also, while not being a problem, it is easier to place the paths you are using inside variables and use the variables instead of the literals
set "sourceFolder=E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV"
set "targetFolder=\\10.10.10.10\scenarios"
if exist "%sourceFolder%\*Nursing*.csv" (
ren "%sourceFolder%\*Nursing*.csv" names.csv
move /y "%sourceFolder%\names.csv" "%targetFolder%\Nursing"
) else if exist ""%sourceFolder%\*Midwifery*.csv" (
ren "%sourceFolder%\*Midwifery*.csv" names.csv
move /y "%sourceFolder%\names.csv" "%targetFolder%\Midwifery"
) else (
echo. Not files detected!
)
And once we are using variables to store the fixed data, we can start to use variables to hold the changing data. As the code being executed is always the same, identify the changing parts in the executed code and use for commands to iterate over the changing information and files on folders
#echo off
setlocal enableextensions disabledelayedexpansion
set "sourceFolder=E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV"
set "targetFolder=\\10.10.10.10\scenarios"
for /l %%z in (0) do (
setlocal enabledelayedexpansion
echo(!time! - Searching files ....
endlocal
set "found="
for %%a in ( Nursing Midwifery XXXX YYYY ) do (
for %%b in ("%sourceFolder%\*%%~a*.csv") do (
move /y "%%~fb" "%targetFolder%\%%~a\names.csv"
set "found=1"
)
)
if not defined found echo(.... No file detected !
timeout /t 1
echo(
)
for /l %%z defines an infinite loop (just to avoid the self call in the batch file or a goto command to a label)
for %%a will iterate over the list of "arguments". For each element in the list, the replaceable parameter %%a will hold its value and expose it to the code in the do clause, where %%~a (the value inside the replaceable parameter without quotes if present) is used to search files and determine target folder.
for %%b will search files. In this case the replaceable parameter %%b will hold a reference to the found file. This reference is later used to move the file (%%~fb is the full path to the file being referenced by %%b)
Maybe something like this. You can expand this by having a list of the file names you want to check against the server's directory. So the script then will loop at the files that matches that of your target list.
#echo off
SETLOCAL
if not exist \\deviceName\e$\directory\filename.csv (
echo filename.csv not found!
) else (
ren \\deviceName\e$\directory\filename.csv filename2.csv
move /-Y \\deviceName\e$\directory\filename2.csv \\deviceName2\e$\director\filename2.csv
if not exist \\device\e$\diretory\filename3.csv (
echo filename3.csv not found!
) else (
ren \\deviceName\e$\directory\filename3.csv filename4.csv
move /-Y \\deviceName\e$\directory\filename4.csv \\!deviceName2\e$\director\filename4.csv
)
)
ENDLOCAL
EXIT
Here is a powershell script that will cleanly handle an arbitrary number of departments and still be easy to maintain.
$DepartmentList = "Nursing","Midwifery","Ortho","Pedi"
$SourceFolder = "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV"
$DestFolder = "\\10.10.10.10\scenarios\"
ForEach($Dept in $DepartmentList)
{
if(Test-Path "E:\inetpub\wwwroot\sim_blitzv15_MSSQL\CSV\*$Dept*.csv")
{
Move-Item "$SourceFolder\*$Dept*.csv" -Destination "$DestFolder\$Dept\names.csv" -Force
$FileFound = $true
}
}
If(-not ($FileFound))
{
Write-Warning "Not files detected!"
}
If you are not using powershell yet, this is a great starter project to make that switch with.