Batch script to add part of parent folder name to pdfs inside - windows

I have a windows directory which contains folders with names like:
Lot 1
Lot 2
Lot 5
Lot A
Block A
Block C
Each of these folders contains PDF survey drawings. The names of the files are inconsequential. My goal is to prefix each PDF in ONLY LOT FOLDERS with an edited version of the name of its parent folder. Instead of adding the prefix Lot 1_ to the filenames of files in folder Lot 1 I would like to add L1_ to the filename.
Currently, I have a batch file which will add any prefix entered into a prompt to all PDFs in current folder. This means I have to go into each folder & run the batch script. This is tedious as I have thousands to deal with.
This is what the code looks like:
Set /p prefix="Enter Prefix to add to file names: "
FOR /f "delims=" %%F IN ('DIR /a-d /b *.PDF') DO (RENAME "%%F" %prefix%_"%%F")
I have been messing around trying to create a batch file to iterate through all folders with Lot and a space in their names and so far all I can do is use a for loop to get all the Lotwhatevernumber names and output them to a text file.
This is what that code looks like:
for /f "delims=" %%F in ('dir /A:D /b Lot*') do echo %%F >> folders.txt
and then I get text file with:
Lot 1
Lot 2
Lot 5
Lot A
I can also output just the number portion of the Folder name. That code:
for /f "tokens=2" %%F in ('dir /A:D /b Lot*') do echo %%F >> folders2.txt
and then I get text file with:
1
2
5
A
I felt like I was real close with that last one, but what I tried to do was instead of echoing to folders2.txt I wanted to enter another for loop where I would rename each file in Lot %%F and add a prefix of L%%F and the rest of the filename.
Anyone has any ideas?
Someone from another forum gave me this which works but the first file in each Lot folder gets named twice...I can't figure out why.
Someone on another forum provided the following which works but the first file in each Lot folder gets labelled L_ twice and I don't know why....
#echo off & setlocal
for /f "tokens=*" %%a in ('dir /b /ad lot*') do (
for %%b in ("%%a"\*.pdf) do call :xx "%%~dpb" "%%~nxb"
)
goto :eof
:xx
set z=%~1
set z=%z:~0,-1%
for %%c in ("%z%") do set k=%%~nc
set k=%k:lot =L%
echo ren %1%2 %k%_%2
ren %1%2 %k%_%2

What about this:
#echo off
rem // Switch to the target directory:
pushd "D:\Target" && (
rem /* Loop through all directories whose names begin with `Lot` + SPACE;
rem the `findstr` portion further filters the directory names so that
rem they must begin with `Lot` + SPACE + a character other than SPACE;
rem everything starting at a potential following SPACE is ignored: */
for /F "tokens=1-2" %%C in ('
2^> nul dir /B /A:D "Lot *" ^| findstr /I "^Lot [^ ]"
') do (
rem /* Loop through all `*.pdf` files in the currently iterated directory;
rem the `findstr` portion further filters the file names so that they must
rem not equal `L` + the second token from the outer loop + something containing
rem a `_` + `.pdf`, because such files are considered as already renamed: */
for /F "delims=" %%F in ('
2^> nul dir /B /A:-D "%%~C %%~D\*.pdf" ^| findstr /I /V "^L%%~D_.*\.pdf$"
') do (
rem // Check whether target file name already exists:
if exist "%%~C %%~D\L%%~D_%%F" (
rem // Collision, hence skip file and return error message:
>&2 echo Collision: cannot rename "%%~C %%~D\%%F" to "L%%~D_%%F"!
) else (
rem // No collision, so actually rename the currently iterated file:
ECHO ren "%%~C %%~D\%%F" "L%%~D_%%F"
)
)
)
rem // Return to original working directory:
popd
)
After having tested for the correct output, remove the upper-case ECHO from the ren command!

Related

~t returning blank instead of time

I'm trying to get the name and time of the oldest file in a folder (By modification date).
I can get the name without any problem using this code
for /f "delims=" %%x in ('dir /b /o-d /a-d %currentfolder% ^| grep -v / ') do (SET FILEINFO=%%x )
From my understanding swapping the %%x for %%~tx should return the modified time instead of the filename. But I get a blank instead.
for /f "delims=" %%x in ('dir /b /o-d /a-d %currentfolder% ^| grep -v / ') do (SET FILEINFO=%%~tx )
The following code returns the time of a file in the folder but not the oldest one.
for %%a in (%currentfolder%\*) do (set LAST_TIME=%%~ta)
I tried to combine the first and last code to get the time of the oldest file but it also returns a blank.
for %%b in (%currentfolder%\%FILEINFO%) do (set MAXDATE=%%~tb)
What is the error here ? How can I solve this ?
Thank you very much for the help
You are almost there:
#echo off
set "currentfolder=D:\some directory\"
pushd "%directory%"
for /f "delims=" %%i in ('dir /b /a-d /od') do (
set "file=%%i"
set "moddate=%%~ti"
goto :done
)
popd
:done
echo %file% %moddate%
So we sort by date (oldest first) then set the first filename as %file% and it's date to %moddate% then we exit the loop so it does not do the same for the other files in the folder.
The problem is caused by the fact that your current working directory referred to by for /F is not the same as the directory you are searching files in by dir.
This can be fixed like this (omitting grep as I do not understand its purpose here):
rem // Temporarily change to the directory containing the files of interest:
pushd "%currentfolder%"
rem /* The current working directory is now the target directory;
rem thus both `dir` and `for /F` work in the same directory: */
for /F "delims=" %%x in ('dir /B /A:-D /O:-D') do (set "FILEINFO=%%~tx")
rem // Restore the former working directory:
popd
rem // Just output the gathered information:
echo/%FILEINFO%
Alternatively, the pushd command line could be replaced by cd /D "%currentfolder%" when popd is removed, given that you do not need the original working directory to be restored.
To understand what was going on in your original code, let us assume:
the current working directory is C:\TEST;
the content of variable currentfolder is D:\DATA;
the directory C:\TEST contains nothing but the batch file;
the directory D:\DATA contains a file called some.txt;
The command line dir /b /o-d /a-d %currentfolder% returns only pure file names (due to its option /B), so based on the predefined sample data, the output would be:
some.txt
Now this text is captured by the for /F loop. Now the last modification date/time is queried by %%~tx, which of course requires access to the file system. Remember that the current working directory is C:\TEST, so the for /F loop tries to gather the information from the following file:
C:\TEST\some.txt
Since such a file does not exist, the output is blank.
To prove that, simply place a new file some.txt into the directory C:\TEST, then you would receive the last modification date/time of that file.

BATCH: Delete parts of filename using substring not working

I have several .csv files in one folder. They are saved automatically but with spaces and execution date and time (in seconds) with amount of containing lines.
So far I was not able to run my powershell script with files containing spaces. So I tried to rename filenames using batch. so far nothing is working fine. Either in cmd-line or with a batch file.
Trying to loop in folder to find .csv is working but defining a string and then substring parts of the file not.
for %%i in ('dir *.csv /b /s') do set string = %%~ni
set substr=!string:~20,25!
echo !substr!
I tried first to use % instead of ! but didn't worked as well. Tried to use pipes for the loop as well, didn't worked.
So far my output is just
!string:~20,25!
My output has to be just the "real" filename of the report without anything else before or after it.
For example, do with that path and filename
C:\Users\Username\CSV_Files\Reportoutput Report_2017 2018-01-09T07_10_33.1924R.csv
this
C:\Users\Username\CSV_Files\Report_2017.csv
When I'm able to extract just the filename without any spaces or leading chars like "Reportoutput" (which is always the same) or starting time of report or containing lines in the report I could use that string and combine it with the path where files are saved.
Any ideas? Why is my "substring" not working at all? Do I miss some action? Some code?
I'm using windows.
Based on the file name structure you've presented and looping in one folder, (the current directory), as stated and used in your example code:
#Echo Off
For %%A In ("* * *.csv"
) Do For /F "Tokens=2" %%B In ("%%~nA") Do Ren "%%~A" "%%B%%~xA"
If you wanted to check inside subfolders of the currect directory then change it to this:
#Echo Off
For /R %%A In ("* * *.csv"
) Do For /F "Tokens=2" %%B In ("%%~nA") Do Ren "%%~A" "%%B%%~xA"
…and if you want to specify the base directory name then you can do so like the following two examples which use %UserProfile% for demonstration purposes, (change as appropriate).
#Echo Off
For /R "%UserProfile%" %%A In ("* * *.csv"
) Do For /F "Tokens=2" %%B In ("%%~nA") Do Ren "%%~A" "%%B%%~xA"
and:
#Echo Off
CD /D "%UserProfile%" 2>Nul||Exit /B
For /R %%A In ("* * *.csv"
) Do For /F "Tokens=2" %%B In ("%%~nA") Do Ren "%%~A" "%%B%%~xA"
Instead of splitting the names using character numbers, this simply takes the second token of the file name string delimited by spaces and adds the original file extension to it in a rename command.

List all files with 2 timestamps, size, but without path or dir

Windows, Command Prompt, need to generate a .txt file output containing of all files from a big and complex dir tree with one (1) line for each files as:
CreationDateYYYYMMDD-HHMMSS, LastModifiedYYYYMMDD-HHMMSS, filesize[no K commas], filename.ext
for example:
20100101-174503, 20120202-191536, 1589567, myfile.ext
The list should not contain lines of dir name entries, etc., only filenames, even if the same file is present in more than once. Time in 24 hours format.
dir /s/t:c/t:w/-c > filelist.txt
command does not exactly works this way.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=c:\program files"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*" '
) DO (
FOR %%d IN (timewritten timecreated) DO SET "%%d="
FOR %%k IN (-d s h) DO (
IF NOT DEFINED timewritten FOR /f "tokens=1,2 delims= " %%d IN ('dir /tw %%~k "%%a" 2^>nul ^|find "%%~nxa"') DO SET "timewritten=%%d %%e"
IF NOT DEFINED timecreated FOR /f "tokens=1,2 delims= " %%d IN ('dir /tc %%~k "%%a" 2^>nul ^|find "%%~nxa"') DO SET "timecreated=%%d %%e"
)
ECHO !timecreated! !timewritten! %%~za %%~nxa
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
Interesting problem. This code processes it by
First, applying the standard directory-list for filenames on the tree from the relative root (%sourcedir%) to %%a
Using the full filename in %%a, set timewritten and timecreated from an ordinary dir list targeting the file in question.
It appeared that %%~ta didn't play nicely to extract the timestamp for hidden and system files, so I decided to build them from the ordinary dir listing with the appropriate t setting, specifically listing with /a-d, /as and /ah and filtering for the line which matched the filename, which seemed to extract the data appropriately.
I left the date/time in raw format. It should be an easy task to extract the various elements and construct the report in the format you want.
This question is a dupe of the SO post cmd dir /b/s plus date, but posting what worked for me:
#echo off
REM list files with timestamp
REM Filename first then timestamp
for /R %I in (*.*) do #echo %~dpnxI %~tI
#echo off
REM list files with timestamp
REM Timestamp first then name
for /R %I in (*.*) do #echo %~tI %~dpnxI
The above are the versions that you would directly paste into a command prompt.
If you want to use these in a batch file and log the output, you could do something like:
rem: Place the following in a batch file such as DirectoriesBareWithTS.cmd.
rem: As the first step in the batch file, net use to the directory or share you want the listing of
rem: Change to your target directory
Y:
for /R %%I in (*.mp4) do #echo %%~tI %%~dpnxI
Then you can pipe the output to a log file when you execute:
DirectoriesBareWithTS.cmd > C:\temp\GiantLongDirListing.log
You could then import that log into Excel.

Copying files with name containing just numbers using a batchfile

I have a Directory with a deep Directory->Sub-directory tree structure. I need to write a batch file to copy all the numbered files (files with names as digits and no alphabetic characters) from all the sub-directories.
For example, a sub-directory might contain the following files:
WR10091.txt
AX10091.htm
10091.txt
AX10091.xml
10091.xml
I need to copy 10091.txt and 10091.xml to another location. I can copy files like AX10091.xml and AX10091.htm by specifying AX*.*. But I cannot figure out how to copy just numbered files with no alphabetic characters. There are thousands of directories and the directory structure does not have any pattern (the depth of a tree branch can vary considerably).
Any help will be appreciated.
#echo off
setlocal enableextensions disabledelayedexpansion
set "source=%cd%"
set "target=x:\target\folder"
for /r "%source%" %%a in (*) do (
(for /f "delims=0123456789" %%b in ("%%~na") do (
break
)) || echo copy "%%~fa" "%target%"
)
In this code the for %%a will iterate over all the files under the indicated folder. For each of them, the for /f %%b will try to tokenize the file name (%%~na) using numbers as delimiters. If the file name only contains numbers, there will be nothing to process (only delimiters) and the inner for raises errorlevel. This is checked with conditional execution (the code after the || is executed if the previous command fails) and if errorlevel was raised the copy operation is echoed to console.
If the output is correct, remove the echo to perform the copy.
note: the break in the inner for loop is included just to have a command that does nothing when files with non numeric names are found.
#echo off
for /f "tokens=* delims=" %%a in ('dir /b /s /a:-d "*"') do (
echo %%~na|findstr /e /b /r "[1-9]*" >nul 2>nul && (
copy %%~fa c:\somewhere\
)
)
should be executed in the same directory as the files.
for /f "delims=" %%a in ('dir /b/s/a-d ^| findstr /reic:"\\[0-9][0-9]*\..*" /c:"\\[0-9][0-9]*"') do copy "%%~a" "targetDir"
This might not work with XP and/or Vista, but this can be fixed if needed (see What are the undocumented features and limitations of the Windows FINDSTR command).

How to batch rename files in a directory from a list of names in a text file

I'd like to use Power Shell or a batch file to rename several files in a folder based on a list in a text file. Essentially I want to append the file names with the author's last names (which I have stored in a separate text file).
E.g. Currently I have:
C:\myfiles
9-ART-2013.pdf
4-EGO-2013.pdf
2-ART-2013.pdf
My text file (in same order as files):
C:\myfiles
_Smith
_Jenkins
_McMaster
I want the files to be renamed as follows:
9-ART-2013_Smith.pdf
4-EGO-2013_Jenkins.pdf
2-ART-2013_McMaster.pdf
I've seen similar problems where people want to recursively rename files but they are always using a generic common appending element like adding an underscore or pre-pending with folder name, etc.
e.g. https://serverfault.com/questions/6268/easy-way-to-rename-all-files-in-a-directory-in-windows
In PowerShell it would be:
$names = Get-Content c\myfiles
Get-ChildItem C:\somedir\*.pdf | Sort -desc |
Foreach {$i=0} {Rename-Item $_ ($_.basename + $names[$i++] + $_.extension) -WhatIf}
If it looks like it will copy correctly, remove the -WhatIf.
Any of the above are likely workable solutions with just a little tweaking but the simplest thing to do was to simply create one text file with each row containing "the current filename"... a TAB... then "the filename I wanted".
9-ART-2013.pdf 9-ART-2013_Smith.pdf
4-EGO-2013.pdf 4-EGO-2013_Jenkins.pdf
2-ART-2013.pdf 2-ART-2013_McMaster.pdf
Then save the file as rename_list.txt and create a batch file with the following code.
for /F "tokens=1,2" %%a in (rename_list.txt) do ren "%%a" "%%b"
pause
You can delete the pause line once you get it tweaked and running correctly. Just copy the rename_list.txt and batch files to the folder with the files you want to rename and run the batch file. If you have a large folder with many files names you can get them in a text file by running a batch file with the following line.
dir /D > filename_scrapper_output.txt
It will create a text file filename_scrapper_output.txt that you can use to start your rename_list.txt file for above.
Another way to achieve the same thing:
#echo off
setlocal EnableDelayedExpansion
rem Load the list of authors:
set i=0
for /F %%a in (myfiles.txt) do (
set /A i+=1
set "author[!i!]=%%a"
)
rem Do the rename:
set i=0
for /F %%a in ('dir /b *.pdf') do (
set /A i+=1
for %%i in (!i!) do ren "%%a" "%%~Na!author[%%i]!%%~Xa"
)
EDIT: New method added
If the list of names file have the "OLD-Name NEW-Name" structure, then the code is much simpler:
for /F "tokens=1,2" %%a in (myfiles.txt) do ren "%%a" "%%b"
Note that the names must be separated by a space.
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
<Text.txt (
for /f "tokens=1*delims=_" %%a in ('dir /b /a-d /o-d *-*-*.pdf') do if "%%b"=="" (
set "xand="
set /p "xand="
echo ren "%%~a" "%%~na!xand!%%~xa"
))
Taking Endoro's and simplifying:
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
<texts.txt (
for /f "tokens=* delims=* " %%a in ('dir /b /a-d /o-d *-*-*.pdf') do (
set "xand="
set /p "xand="
ren "%%~a" "%%~na!xand!%%~xa"
))

Resources