Renaming text files by reading last word of 2nd line - batch-file

I have a large number of text files.
I need a batch script that reads each file, and renames it to the last word of second line.
The last word of 2nd line of these text files is unique within the given set of files.

#ECHO OFF
SETLOCAL
SET "sourcedir=."
FOR /f "delims=" %%a IN ('dir /b /a-d "%sourcedir%\*.txt"') DO (
SET "found="
FOR /f "skip=1delims=" %%b IN ('type "%sourcedir%\%%a"') DO IF NOT DEFINED found (
SET "found=%%b"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "found=!found:"=!"
SET "found=!found: =.!"
FOR /f %%c IN ("!found!") DO SET "found=%%~xc"
ECHO REN "%sourcedir%\%%a" "!found:~1!.txt"
ENDLOCAL
)
)
GOTO :EOF
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO REN to REN to actually rename the files.

Related

Batch folder creation based on part of file name, without keeping extension

Trying to create a script that will take the third token of a file name, create a folder based on it and move the associated file to that folder.
Have got this so far:
#ECHO OFF
SETLOCAL
SET "sourcedir=D:\Sourcedir"
PUSHD %sourcedir%
FOR /f "tokens=1,2,3,4 delims=" %%a IN (
'dir /b /a-d "*.pdf"'
) DO (
ECHO MD %%c
ECHO MOVE "%%a %%b %%c %%d" .\%%c\
)
POPD
GOTO :EOF
Only problem is the folder being created is including the file extension where as I just need the folder to be named the third token.
Example file name:
"File Number 10.pdf
Expected folder name:
10
Thanks
Why did you use delims=? This will remove delimiter, and take whole line to %%a.
Try this:
#ECHO OFF
SETLOCAL
SET "sourcedir=D:\Sourcedir"
PUSHD %sourcedir%
FOR /f "tokens=1,2,3" %%a IN (
'dir /b /a-d "*.pdf"'
) DO (
ECHO MD %%~nc
ECHO MOVE "%%a %%b %%c" .\%%~nc\
)
POPD
GOTO :EOF
When no delims= set, it will use space. So %%c will be 10.pdf, ~n is to extract its name part.
This is based on your question, which you can concatenate %%a %%b %%c together with spaces, then it's simple.
If your filenames are more complicated, then an inner for loop is better.
-- Which another question already gave a great solution.
Here's an alternative, which will just use the last space delimited string/number, regardless of how many there are, (if there are none it will use the whole filename)!
#Echo Off
For %%A In ("D:\Sourcedir\*.pdf") Do Call :L "%%A"
Exit /B
:L
Set "F=%~n1"
Set "F=%F: ="&Set "F=%"
If Not Exist "%~dp1%F%\" MD "%~dp1%F%"
Move /Y %1 "%~dp1%F%"
And if you wanted to move only those which have at least one space, you can include that inside the For parentheses.
#Echo Off
For %%A In ("D:\Sourcedir\* *.pdf") Do Call :L "%%A"
Exit /B
:L
Set "F=%~n1"
Set "F=%F: ="&Set "F=%"
If Not Exist "%~dp1%F%\" MD "%~dp1%F%"
Move /Y %1 "%~dp1%F%"
You can run 2 for loops get the full name in the first, then split the name in the second loop, get the 3rd token, create the directory and then copy the actual file name from the first loop.
This way you do not need to try and patch the name together again, I know it works, but it is ugly and not prefered:
#echo off
setlocal enabledelayedexpansion
set "sourcedir=D:\Sourcedir"
pushd %sourcedir%
for %%a in (*.pdf) do (
set "var=%%a"
for /f "tokens=3" %%i in ("!var!") do (
echo md "%%~ni"
echo move "%%~a" "%%~ni"
)
)
popd
goto EOF
For more information on these commands, see help for each from cmd.exe i.e
for /?
set /?
setlocal /?
set and setlocal has very specific information regarding delayed expansion.

Search file names from one list and replace them with another list in BATCH

I have two files :
old_names.txt
oldname1
oldname2
new_names.txt
newname1
newname2
I would like to search my folder for file names containing "old_names" and replace "old_name" string with corresponding "new_name".
for /f %%i in (old_names.txt) do (
// get corresponding %%j new_name
for /f %%a in ('dir /b /a-d *%%i*') do ren %%a %%j
)
How can I retrieve the corresponding new_name ?
For your file pair concept you basically need to read the two files line by line simultaneously, if I understand correctly, which can be accomplished like illustrated in this answer. So here is a possible code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=D:\path\to\root_dir" & rem // (directory containing files to rename)
set "_FILE1=D:\path\to\old_names.txt"
set "_FILE2=D:\path\to\new_names.txt"
rem // Count number of lines of 1st file (2nd file is not checked):
for /F %%C in ('^< "%_FILE1%" find /C /V ""') do set "NUM1=%%C"
setlocal EnableDelayedExpansion
rem // Change into root directory:
cd /D "%_ROOT%" || exit /B 1
rem // Here input redirection is used to read both files simultaneously:
9< "!_FILE1!" 8< "!_FILE2!" (
rem // Loop through the number of lines of the 1st file:
for /L %%I in (1,1,%NUM1%) do (
rem // Read a line from the 1st file:
<&9 (set "LINE1=" & set /P "LINE1=")
rem // Read a line from the 2nd file:
<&8 (set "LINE2=" & set /P "LINE2=")
rem /* Assign line strings to `for` variables to later avoid nested
rem delayedly expanded environment variables: */
for /F "tokens=1,2 delims=| eol=|" %%I in ("!LINE1!|!LINE2!") do (
rem // Get list of files matching the partial name:
for /F "delims= eol=|" %%F in ('dir /B /A:-D "*!LINE1!*"') do (
endlocal
rem // Store current file name:
set "NAME=%%F"
setlocal EnableDelayedExpansion
rem // Do the actual sub-string replacement and rename file:
ECHO ren "!NAME!" "!NAME:%%I=%%J!"
)
)
)
)
endlocal
endlocal
exit /B
After having checked the correct output, remove the upper-case ECHO command!
This does not work if any of the following characters occur in the two name files: =, !, ^; the ~ must not occur as the first character in any line of the first file (old names).
As per my comment. Create a single file called names.txt and add the strings you want to replace and what you want to replace it with:
dummy replacement
dummy2 replacement2
then the script needs to be in the same directory, or you have to specify path to the files:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2" %%i in (names.txt) do (
for /f %%a in ('dir /b /a-d ^| findstr "%%i"') do (
set "oldname=%%a"
set "newname=!oldname:%%i=%%j!"
echo ren "!oldname!" "!newname!"
)
)
or by specifying path:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2" %%i in (names.txt) do (
for /f %%a in ('dir /b /a-d "D:\PATH" ^| findstr "%%i"') do (
set "oldname=%%a"
set "newname=!oldname:%%i=%%j!"
echo ren "!oldname!" "!newname!"
)
)
Once you are happy that it prints the files to replace to screen, simply remove the echo from the last line of code to actually perform the ren

Remove duplicate value in csv on combine

I encountered the below code online and modified this on my need.
I just wanna ask since i am new to batch file if there is a way to remove duplicate values after the combine.
#echo off
ECHO Set working directory
pushd %~dp0
ECHO Deleting existing combined file
del combined.csv
setlocal ENABLEDELAYEDEXPANSION
set cnt=1
for %%i in (*.csv) do (
if !cnt!==1 (
for /f "delims=" %%j in ('type "%%i"') do echo %%j >> combined.csv
) else if %%i NEQ combined.csv (
for /f "skip=1 delims=" %%j in ('type "%%i"') do echo %%j >> combined.csv
)
set /a cnt+=1
)
#ECHO OFF
SETLOCAL
ECHO Set working directory
pushd %~dp0
ECHO Deleting existing combined file
del combined.csv
set "flag="
for %%i in (*.csv) do if %%i NEQ combined.csv (
IF DEFINED flag (
findstr /l /x /v /g:combined.csv "%%i">#.vsc
TYPE #.vsc >>combined.csv
) ELSE (
COPY "%%i" combined.csv >nul
SET flag=y
)
)
DEL #.vsc /F /Q
POPD
GOTO :EOF
This may suit you better.
It uses a simple setlocal rather than the delayedexpansion version, initialising flag to empty then setting it within the loop and using if defined which works on the run-time value of flag.
First time through, it simply copies the detected source file to combined.csv and then sets flag to a value so it's ow defined
each other time through, findstr outputs those lines in the source file %%i that /v do not /x exactly match /l literally /g:filename any line in the combined.txt file TO a tempfile I'be nominated as #.vsc (name not important). Then that file is appended to combined.csv
Consequently, provided any particular .csv is free of duplicate lines within itself, the combined.csv will also be free of duplicate lines.
Since the header line is evidently identical in every file, the initial copy of the first file will place the header into combined.csv and hence findstr will neatly exclude it thereafter.
Revision to combat evil unicode:
#ECHO OFF
SETLOCAL
ECHO Set working directory
pushd %~dp0
ECHO Deleting existing combined file
del combined.csv
set "flag="
for %%i in (*.csv) do if %%i NEQ combined.csv (
(FOR /f "delims=" %%j IN ('type "%%i"') DO ECHO %%j)>#.vsc
IF DEFINED flag (
findstr /l /x /v /g:combined.csv "#.vsc" >##.vsc
TYPE ##.vsc>>combined.csv
) ELSE (
REN #.vsc combined.csv
SET flag=y
)
)
DEL #.vsc /F /Q
DEL ##.vsc /F /Q
POPD
GOTO :EOF
I suspect that the problem is using UNICODE within your files. Cutting-and-pasting your data showed that it was unicode.
The for /f... ceremony reads unicode and produces ASCII, hence this version first simply converts to ASCII using your familiar technique then operates on the converted file #.vsc. findstr does not appreciate outputting to the same file as it's attempting to read as /g:, so a further tempfile ##.vsc is used for the findstr output.
Note that the unicode characters between (header) Last modified and date and also elsewhere will be replaced by question-marks.

Renaming .txt files in bulk

I downloaded about 34000 books in .txt format from Project Gutenberg. Now I want to rename all of them by its content. For example every text file includes its "Title" and "Author's Name" so I want to rename all the text files on its "Title" and "Author's Name" by some commands.
I created a batch file. It runs but is not renaming the files. This is my code:
#echo off&setlocal
cd E:\Test
for /f "delims=" %%i in ('dir /a-d/b *.txt') do (
set "nname="
set "fname=%%~i"
for /f "usebackqskip=7delims=" %%f in ("%%~i") do if not defined nname
set "nname=%%f"
setlocal enabledelayedexpansion
set "nname=!nname:~0,40!"
echo rename "!fname!" "!nname!"
endlocal
)
You can use this as a base
#echo off
setlocal enableextensions disabledelayedexpansion
rem Change to source folder
pushd "e:\test" && (
rem Where the renamed files will be placed to avoid re-rename
if not exist renamed\ md renamed
rem For each input file
for %%f in (*.txt) do (
rem Retrieve the data from inside the file
set "author=" & set "title="
for /f "tokens=1,* delims=: " %%a in ('
findstr /b "Author: Title:" "%%~ff"
') do if not defined %%a set "%%a=%%b"
rem If the fields have been retrieved then do the rename
if defined author if defined title (
setlocal enabledelayedexpansion
for /f "delims=" %%a in ("!author! - !title!") do (
endlocal
echo move "%%~ff" "renamed\%%a%%~xf"
rem NOTE: operation is only echoed to console
rem if console output seems correct, then
rem remove the echo command
)
)
)
rem Done. Return to previous active directory
popd
)
Of course, filesystem has rules about what is allowed in a file name and, not knowing what kind of characters can be found, this code could and probably will fail to rename some files.
Your current script will just print the rename commands, not execute them. You should remove echo (after checking what it produces) in this line:
echo rename "!fname!" "!nname!"
Your script also has a few formatting issues. There should be spaces like this:
for /f "usebackq skip=7 delims=" %%f in ("%%~i") do
And there should be no newline just after:
if not defined nname

Changing folder name with names from a file using batch

I want to write a batch script to rename folders in a directory.
The way that would work is, I would have a file that contains names that I would like each folder to be renamed with. So basically the batch script would just pick names from the file (that contains names) and use it to rename each folder.
So if I have 20 folders, 20 names would exist in file to rename each folder.
What I have so far:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET old=*.txt
SET new="c:\Users\user\Desktop\testing.txt"
< %new% (for /f "tokens=*" %%f in ('dir /b %old%') do (
ren Read the next name from the redirected input file
SET /P newname=
ren "%%f" "!newname!"
))
The above script didn't give me the desired result.
Not tested:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET old=*.txt
SET new="c:\Users\user\Desktop\testing.txt"
set counter=0
(for /f "tokens=*" %%f in ('dir /b %old%') do (
ren Read the next name from the redirected input file
set /a counter=counter+1
for /f "tokens=1* delims=:" %%a in ('findstr /R /N "^" "%new%"^|find "!counter!"') do set "newname=%%b"
ren "%%f" "!newname!"
)
The problem is that the dir /b %old% command generate a list of files with .txt extension. If you want to rename folders, then include /AD switch and eliminate the wild-card:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET new="c:\Users\user\Desktop\testing.txt"
< %new% (for /f "tokens=*" %%f in ('dir /b /AD') do (
ren Read the next name from the redirected input file
SET /P newname=
ren "%%f" "!newname!"
))

Resources