I have to rename a bunch of files. They're all in the same folder. My idea was to do this by a batch script, but the problem is, that I have to "split" the original filename and give it an indexing number.
For example:
Original Filename: XYZ SomeDocument.docx
New Filename: XYZ 01 SomeDocument.docx
Does anybody have an idea how I can do this?
#echo off
setlocal EnableDelayedExpansion
set index=100
for /F "tokens=1*" %%a in ('dir /B /A-D') do (
set /A index+=1
ren "%%a %%b" "%%a !index:~-2! %%b"
)
I always use Python for tasks like this :)
Eg:
import os
DIR = r'C:\foo'
index = 1
for file_name in os.listdir(DIR):
old_path = os.path.join(DIR, file_name)
split = file_name.split("XYZ")
new_file_name = "XYZ %s %s" % (index, split[1].strip())
new_path = os.path.join(DIR, new_file_name)
os.rename(old_path, new_path)
index += 1
Related
I usually like to try to work these out myself, but at the moment I have to admit I don't know where to start with this one. Hoping someone could kindly steer me in the right direction at least.
I have a folder with a number of .txt files
Text1.txt
Text2.txt
Text3.txt
In my windows bat file I need to list the contents of said folder and set them as options to be set as variables.
example:
cls
echo[
echo[ Please select an option
echo[
echo (1) Text1
echo (2) Text2
echo (3) Text3
echo[
set /p option=Type your selection (1-3) and press ENTER=
if !option!==1 set var=Text1
if !option!==2 set var=Text2
if !option!==3 set var=Text3
Any advice is greatly appreciated, this forum has been great.
*Edit
here is something I tried
cls
echo[
echo[ Please select an option
echo[
dir /b "*.txt"
echo[
set /p option=Type your selection (1-3) and press ENTER=
if !option!==1 set var=text1
if !option!==2 set var=text2
if !option!==3 set var=text3
it works, but does not add the numbers (1) before the options, and it also has them aligned left not centred.
Please select an option
text1.txt
text2.txt
text3.txt
Type your selection (1-3) and press ENTER=
There are different solutions you can build, here are 2 examples.
If you have only a few files you can utilize choice:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
echo %%i. %%j
set "cnt=!cnt!%%i"
set "fchoice%%i=%%~j"
)
choice /c %cnt% /m "Choose"
echo you chose !fchoice%errorlevel%!
if you have many files though, choice might not be a viable option, then revert to set /p:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
echo %%i. %%j
set "cnt=!cnt!%%i"
set "fchoice%%i=%%~j"
set "fin=%%i"
)
set /p "chosen=Select a file by number: "
for /l %%i in (1,1,%fin%) do if "%chosen%" == "%%i" set "check=1"
if not defined check echo Incorrect choice selected & goto :EOF
echo you chose !fchoice%chosen%!
Well, if this were any other language what would you do? Probably populate an array with your directory listing, right? Then use that array to pair menu option with file choice? Well, don't let the fact that the Batch language doesn't have arrays stop you. They're easy enough to simulate.
#echo off & setlocal
rem // init array index
set file.length=0
rem // for each .txt file in the current directory
for %%I in (*.txt) do (
rem // It's good practice only to enable delayed expansion when needed, as
rem // otherwise it can mangle values containing exclamation marks
setlocal enabledelayedexpansion
rem // use a "for /f" command to endlocal while reading the value of
rem // !file.length!. This preserves exclamation marks in file names.
for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
rem // set /a doesn't require delayed expansion. It just works.
set /a file.ubound = file.length, file.length += 1
)
rem // Display the collection of variables named file...something.
set file
There you go. The last line should show you a list of all the variables beginning with file, including the simulated .length and .ubound properties. From there, just use a for /L %%I in (0, 1, %file.ubound%) to display your menu.
Here's a bit more. Firstly, I read your comment explaining that the number of txt files could exceed 50. By default, the Windows cmd console is 24 lines. Wouldn't it be nice to columnify the output so the user doesn't have to scroll? I wrote a utility script that will take a flat list and columnify it based on the number of rows in the current cmd console. Save this as...
columnify.bat:
#if (#CodeSection == #Batch) #then
#echo off & setlocal
if "%~1"=="test" (
rem // this errors if there's redirected input buffer waiting
timeout /t 0 /nobreak >NUL 2>NUL && (
echo Usage: command list output ^| %~nx0
echo or %~nx0 ^< txtfile containing a list
echo;
echo Hit Ctrl-C to exit.
)
exit
)
for /f "usebackq tokens=1,2 delims=," %%I in (
`powershell "(Get-Host).UI.RawUI.WindowSize.toString()"`
) do (
rem // detect whether input buffer has content waiting
start /b cmd /c "%~f0" test
cscript /nologo /e:JScript "%~f0" %%I %%J
)
goto :EOF
#end // end Batch / begin JScript hybrid code
var stdin = WSH.CreateObject('Scripting.FileSystemObject').GetStandardStream(0).ReadAll();
cols = WSH.Arguments(0) * 1 - 1,
rows = WSH.Arguments(1) * 1 - 4;
var out = stdin.split(/\r?\n/), buffer = [], maxlen, col = 0;
if (rows > out.length) { rows = out.length; }
while (out.length) {
buffer[col] = [];
maxlen = 0;
while (buffer[col].length < rows) {
val = out.length ? out.shift() : '';
buffer[col].push(val);
if (maxlen < val.length) maxlen = val.length;
}
for (var i = buffer[col].length; i--;) {
while (buffer[col][i].length < maxlen) { buffer[col][i] += ' '; }
}
col++;
}
for (var i=0; i < buffer[0].length; i++) {
var line = [];
for (var j=0; j < col; j++) {
line.push(buffer[j][i]);
}
WSH.Echo(line.join(' ').substr(0, cols));
}
Now your main script can make use of columnify.bat by piping output through it.
#echo off & setlocal
rem // All the same stuff as above, but without the comments.
set file.length=0
for %%I in (*.txt) do (
setlocal enabledelayedexpansion
for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
set /a file.ubound = file.length, file.length += 1
)
cls
:displaymenu
echo Always press your luck. Which file do you choose?
echo;
( for /L %%I in (0,1,%file.ubound%) do #(
call echo %%I: %%file[%%~I]%%
) ) | columnify
echo;
set /P "choice=Enter a number: "
if %choice% GEQ 0 if %choice% LEQ %file.ubound% (
setlocal enabledelayedexpansion
echo You chose !file[%choice%]!. Neat.
endlocal
) else (
cls
powershell "write-host -f red 'Invalid response. Enter a number between 0 and %file.ubound%.'"
goto displaymenu
)
I want to read the file name with the command and automatically move it to the folder with the same name. What should I do?
example:
before processing
after processing
If I have files and folders with the same name, I want to move them to a folder with the same name.
What should I do? Do I have a cmd command?
I will provide both a solution to this exact question, and an alternative that I would suggest to handle this situation.
==========
~ Solution ~
==========
Copy/Paste the code below into an empty file, save, and execute.
#echo off
for /f "tokens=1,* delims=_" %%a in ('dir /b *.xlsx') do (
if not "%%a_%%b"=="%~nx0" (
if not exist %%a mkdir %%a
move "%%a_%%b" "%%a\"
)
)
You can change the "*.xlsx" to any other file extension, or change to "*.*" to work with ANY file extension.
Keep in mind though, this ONLY works with filenames that are formatted like the way you mentioned in your question.
===================
~ Alternative Solution~
===================
I would suggest the Shell Extension "Files 2 Folder" as an alternative. I came across a situation where I needed something similar to what you're asking a couple years ago, and this ended up working out great.
https://www.dcmembers.com/skwire/download/files-2-folder/
Here is another approach using regex in vbscript with a batch file :
#echo off & color 0A
Title Extract Title using Regex in vbscript
SetLocal EnableDelayedExpansion
#for /f "delims=" %%a in ('dir /b *.xlsx') do (
Call :Extract_Title "%%a" Title
If Defined Title (
If Not Exist "!Title!\" MkDir "!Title!\"
Move /-Y "%%a" "!Title!\"
)
)
Pause & Exit
::----------------------------------------------------------------------------------------
:Extract_Title <InputFile> <Title to be Set>
>"%tmp%\%~n0.vbs" (
echo WScript.StdOut.WriteLine Extract_Title(Data^)
echo Function Extract_Title(Data^)
echo Data = Wscript.Arguments(0^)
echo Set re = New RegExp
echo re.Global = True
echo re.IgnoreCase = True
echo re.Pattern = "(\S+|\S.+)_"
echo For Each Match in re.Execute(Data^)
echo Title = Match.SubMatches(0^)
echo Next
echo Extract_Title = Title
echo End Function
)
#for /f "delims=" %%A in ('cscript /nologo "%tmp%\%~n0.vbs" "%~1"') do set "%2=%%A"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
Exit /B
::----------------------------------------------------------------------------------------
If I'm on windows 7 and I have a spreadsheet:
1, Ant
2, Brown Bear (note whitespace)
3, Cat
4, Dinosaur
And folders
C:\Directory\1\
C:\Directory\2\
C:\Directory\4\
Is there any way to put in a batch file or a vbs file or whatever the appropriate tool is in that directory that would rename those folders using the spreadsheet? With the final result being:
C:\Directory\1 Ant\
C:\Directory\2 Brown Bear\
C:\Directory\4 Dinosaur\
So far I have a batch file that will append a string to all the folders in the directory it's run in (be cautious where you run it), but I'd just be using if statements for many, many items. Any suggestions on how to connect it to a csv file?
#echo off
for /f "tokens=1,2,* delims=,(" %%a in ('dir /a:d /b') do (
if "%%a" == "10" ( ren "%%a" "%%a Elephant" )
if "%%a" == "11" ( ren "%%a" "%%a Otter")
)
Thanks in advance.
There are a couple unclear points in your question (like the names: are they in a spreadsheet or in a .csv file?) so I made some assumptions. Given a names.csv file with this contents:
1, Ant
2, Brown Bear
3, Cat
4, Dinosaur
The Batch file below achieve the rename you want:
#echo off
setlocal EnableDelayedExpansion
rem Load the array of equivalences from names.csv file:
for /F "tokens=1* delims=," %%a in (names.csv) do set "name[%%a]=%%b"
rem Rename the folders:
cd C:\Directory
for /F "delims=" %%a in ('dir /A:D /B') do ECHO ren "%%a" "%%a!name[%%a]!"
Previous Batch file just show the ren commands; if the output looks good, remove the ECHO part in order to execute the commands.
If names.csv file have a header in the first line, insert "skip=1 " before "tokens" in the first for /F ... command.
Well, if you're OK with using Powershell this little script could help:
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
Import-Csv "D:\Test\ps\look_up.csv" |`
ForEach-Object {
$old = $directorypath + "\" + $_.orig
if(Test-Path($old)){
$newPath = $directorypath + "\" +$_.orig + " " + $_.new
ren $old $newPath
}
}
I had folders named 1,2,3 in the same folder as the script and a csv file with the following content:
orig, new
1, buga boo
2, bla
3, bu
4, none
After running the script the folders were named
Name
----
1 buga boo
2 bla
3 bu
I can compare the count of lines in a file with content of another file
for example:
file1 line count is 10
file2 contains 12
then not equal
using the following script
#ECHO off
rem using linecount and putfileinvar to compare count and datafile
Set _File=testfile.txt
Set /a _Lines=0
For /f %%j in ('Type %_File%^|Find "" /v /c') Do Set /a _Lines=%%j
set /p myvar= < filecount.tmp
rem echo %myvar%%_lines%
IF %myvar% == %_lines% (ECHO eq ) ELSE (ECHO neq )
Now I want do do this for a whole directory and its sub directories where every sub directory contains two files
datafile and its count in a sperate file
I want to compare the number of lines of the datafile with the count file
:: list foleders in the root directory and store them in list file
dir /b /o:n /ad > dirlist.txt
:: for each directory in list
FOR /F "tokens=*" %%v in (dirlist.txt) do (
::store dat file names in each directory in a temp file
::Log inside each folder
cd %%v
::list dat files in file.txt
dir *.dat /b /o:n > file.txt
::for each file stored in file.txt
FOR /F "tokens=*" %%m in (file.txt) do (
::count lines inside dat file
findstr /R /N "^" %%m | find /C ":" > save_temp_count.txt
::Get the contents of the temp file and save it to the %mycount% variable
set /a mycount<=save_temp_count.txt
)
::delete temp files
del file.txt
::Get all files tmp files
dir *.tmp /b /o:n > file.txt
::get file names in file.txt
for /F "tokens=*" %%j in (file.txt) do (
set /a fcount=<%%j
)
if %fcount% == %mycount% (echo 1eq ) else (echo neq & echo %%v >> ../result.txt)
::delete temp files
del file.txt
del save_temp_count.txt
::go up back to parent folder
cd ..
)
copy this and paste it in the root directory where your folders exist , note that this script will not handle unexpected scenarioes , like:
found more than 2 files in a folder.
extensions are different from expected ( dat , tmp ).
tmp files dont contain an integer.
hope this helps.
I am trying to rename all the files present in a Windows directory using FOR command as follows at the command prompt:
for %1 in (*.*) do ren %1 test%1
E.g. This renames a file enc1.ctl to testenc1.ctl enc2.ctl to testenc2.ctl
Thats not what i want. What i want is
enc1.ctl renamed to test1.ctl enc2.ctl renamed to test2.ctl
How do i do that?
#Akelunuk:
Thanks, that w kind of works but i have files names as
h263_enc_random_pixels_1.ctl , h263_enc_random_pixels_2.ctl which i want to rename to
test1.ctl and test2.ctl respectively
Then how?
I've got it!
for %1 in (.) do ren %1 t%1
and then:
ren tenc*.* test*.*
If you know the number of files, (say 10), you can use
for /L %1 in (1,1,10) do ren enc%1.ctl test%1.ctl
I am not sure if it is possible in batch, but then again I never mastered this primitive language... :-P
If CMD isn't mandatory, but you can't use a good file renamer, you can do that with WSH:
var path= "E:/tmp";
var fso = WScript.CreateObject("Scripting.FileSystemObject");
var folder = fso.GetFolder(path);
var files = new Enumerator(folder.files);
for (; !files.atEnd(); files.moveNext())
{
var file = files.item();
var fileName = file.Name;
var p = /^enc(\d+)\.ctl$/.exec(fileName);
if (p != null)
{
var newFileName = "test" + p[1] + ".ctl";
// Optional feedback
WScript.echo(fileName + " -----> " + newFileName);
file.Move(newFileName);
}
}
Of course, put that in a file.js
I actually tested with file.Copy(file.ParentFolder + "/SO/" + newFileName); to avoid loosing files...
HTH.
This renames all files in directory for filter file types with PREFIX and today's date and time
#echo ON
cls
for %%a in (*.pdf) do (set myfiledate=%%~ta echo !myfiledate!)
echo Date format = %myfiledate%
echo dd = %myfiledate:~0,2%
echo mm = %myfiledate:~3,2%
echo yyyy = %myfiledate:~6,4%
echo.
echo Time format = %myfiledate%
echo hh = %myfiledate:~11,2%
echo mm = %myfiledate:~14,2%
echo AM = %myfiledate:~17,2%
echo.
echo Timestamp = %myfiledate:~0,2%_%myfiledate:~3,2%_%myfiledate:~6,4%-%myfiledate:~11,2%_%myfiledate:~14,2%_%myfiledate:~17,2%
ECHO "TEST..." > "test-%myfiledate:~0,2%_%myfiledate:~3,2%_%myfiledate:~6,4%-TIME-%myfiledate:~11,2%_%myfiledate:~14,2%_%myfiledate:~17,2%.txt"
PAUSE
This echos successfuly the date modified and time as a postfix but doesnt parse the info into the rename. I cant figure out why, but it is very close. Maybe someone cant tweak to suit your purpose.
#echo ON
setlocal
cls
for %%a in (*.pdf) do (set myfiledate=%%~ta echo !myfiledate!)
:DATETIME
echo Date format = %myfiledate%
echo dd = %myfiledate:~0,2%
echo mm = %myfiledate:~3,2%
echo yyyy = %myfiledate:~6,4%
echo Time format = %myfiledate%
echo hh = %myfiledate:~11,2%
echo mm = %myfiledate:~14,2%
echo AM = %myfiledate:~17,2%
= %myfiledate:~17,2%
echo.
echo Timestamp = %myfiledate:~0,2%_%myfiledate:~3,2%_%myfiledate:~6,4%-%myfiledate:~11,2%_%myfiledate:~14,2%_%myfiledate:~17,2%
ECHO "TEST..." > "test-%myfiledate:~0,2%_%myfiledate:~3,2%_%myfiledate:~6,4%-TIME-%myfiledate:~11,2%_%myfiledate:~14,2%_%myfiledate:~17,2%.txt"
for /f "delims=" %%a in ('dir *.pdf /t:a /a:-d /b /s') do call :RENAME "%%a"
:RENAME
REM for /f "tokens=1-6 delims=/ " %%a in ('dir %%a /t:w^|find "/"') do (
ren %%a "3DC-test-OFF-ELE-%myfiledate:~0,2%_%myfiledate:~3,2%_%myfiledate:~6,4%-TIME-%myfiledate:~11,2%_%myfiledate:~14,2%_%myfiledate:~17,2%~x1")
PAUSE
GOTO :EOF