Renaming BAT suddenly not working correctly - batch-file

Bit of a strange thing is happening to me.
I put a renaming batch file together a few years ago (with a lot of help from various places, including StackOverflow) for a project i was working on.
It would rename some files and prefix them with the first 5 characters from the parent folder (i.e. '12345 - Site').
I haven't used the BAT file for a good few months and now have a need to, but it is not working correctly.
It is renaming the files, but it is using the whole of the parent folder instead of just the first 5 characters. I have tested it on another PC and run it in folders where it previously worked.
Does anyone have any ideas as to why this would happen, how to fix it, or what I could add to the batch file to achieve the same result?
Just to point out, I am a complete novice and spent many nights getting the first batch file working through trial and error and cutting and pasting from similar batch file requests on the web.
My current code:
for %%z in ("%cd%") do (
for %%a in ("%%~dpz%\.") do (
for /f "delims=" %%i in ('dir /b /a-d *.pdf,*.xlsx,*.docx,*.xlsm') do move "%%i" "%%~nxz %%i"))

This should work for you.
for %%z in ("%cd%") do (
for %%a in ("%%~dpz%\.") do (
for /f "delims=" %%i in ('dir /b /a-d *.pdf,*.xlsx,*.docx,*.xlsm') do call :renameStuff "%%i" "%%~nxz"
)
)
goto :eof
:renameStuff
set "originalName=%~1"
set "parentFolder=%~2"
echo move "%originalName%" "%parentFolder:~0,5% %originalName%"
exit /b
The specific bit you're looking for is %parentFolder:~0,5%, which takes a substring of %parentFolder% starting at character 0 and stopping after 5 characters. This gives you the first 5 characters that you're looking for.
The tricky bit is that you can't use this on those for loop %%z type variables. Thus, you have to pass it to another variable. Further, because you've got some nested loops delayed expansion makes this really ugly, so I've passed the variable into a subroutine (call :renameStuff "%%i" "%%~nxz") which turns those into %1 and %2 type variables, and then passed it into ordinary variables (set "originalName=%~1") that this will work with.

Related

Batch script to iterate through directories starting with a specific string

I'm currently having to manually edit the batch file to manually tell it which directory to work on.
The directories it has to crawl will ALWAYS start with "2020-" (at least for this year), and sometimes there will be multiple of them if I miss a day.
(if it's any easier, they will ALWAYS be in this format: "0000-00-00")
Is there a way to edit this to account for that?
I've tried just making the source_directory just "2020*" but I know that's probably not how this works lol, any help or pointer in the right direction would be amazing.
#echo off
pushd %~dp0
SET source_directory=2020-05-03
SET target_directory=%~dp0
for /f %%a IN ('dir "%source_directory%" /b') do (
move %source_directory%\%%a %target_directory%
)
Sorry, I don't use SO too often so I forget how things need to be done.
This is the solution I've come up with. I don't think it's the intuitive way of doing this, but I don't understand batch well enough to do this without nesting loops.
#echo off
pushd %~dp0
SET source_directory=????-??-??
SET target_directory=%~dp0
for /d %%s in (%source_directory%) do (
for /f %%a IN ('dir "%%s" /b') do (
move %%s\%%a %target_directory%
)
)

Batch programing to search some file in sub folders

I have hundreds of csv files . csv files are stored in folders and sub ​​folders . I want to search fifty csv file whose file names have been determined , for example 1.csv , 2.csv , 3.csv , ... , 50.csv . very troublesome if I searched one by one using the Windows search tool . I would like if the files are found , save in the folder named FOUND . please help to overcome this problem by using the batch programming / bat ? thank you very much
There's a number of approaches one can take, depending on how much automation you require... To help you get started, you may want to look at this it helped me (and indeed continues to do so) when I started learning batch. Furthermore I will provide one possible template for achieving your objective, as I have interpreted it. Perhaps it is not the most elegant or efficient method, but it introduces a number of batch commands that you may or may not have encountered, which in turn may help you develop your own method.
#echo off
setlocal enabledelayedexpansion
echo Please enter a drive letter:
set /p "drive=>"
echo Please enter a search string:
set /p "searchstring=>"
echo %searchstring%>search.txt
set /p search=<search.txt
set /a suffix=0
echo.>>search.txt
:LOOP
for /f "tokens=*" %%i in ("search.txt") do (
set /a suffix=suffix+1
set seq=%search% !suffix!
echo !seq!>>search.txt
)
if !suffix! leq 49 goto LOOP
for /f "tokens=*" %%i in (search.txt) do (
for /f "tokens=*" %%j in ('dir /b /s /a-d %drive%:\"%%i.csv" 2^>nul') do (
if not exist "%~dp0\found" md "%~dp0\found"
move /y "%%j" "%~dp0\found\%%~nxj"
)
)
pause
This is not intended as a definitive solution, though you may find it answers your original query/request. All the best.
Here's another working solution for you..
#ECHO OFF
SETLOCAL EnableDelayedExpansion
REM First Set your directories input and output
SET InputDir=C:\Directory to your CSV files\
SET OutputDir=C:\Directory to your CSV files\FOUND
REM check if the FOUND directory exist, if not, then create it.
IF NOT EXIST OutputDir (
mkdir %OutputDir%
)
REM Grab a scan of the input directory and save it to a temporary file list.
Dir /a /b %InputDir%>"%OutputDir%\Found.txt"
REM Set the files you would like to find.
SET "File1=1.csv"
SET "File2=2.csv"
SET "File3=50.csv"
REM The loop, to process the matching file(s).
FOR %%A IN (%File1%,%File2%,%File3%) DO (
FOR /F "usebackq" %%B IN ("%OutputDir%\Found.txt") DO (
IF %%A==%%B (
copy "%InputDir%\%%A" "%OutputDir%\%%A"
)
)
)
REM Clean up the temp file list.
DEL "%OutputDir%\Found.txt"
Make note, I didn't add quotes to the Input and Output variables, but instead added quotes to the copy portion of the code to compensate for white spaces in your directory path. I tried to keep it simple, so you could follow the logic of how it processed what you are looking for, you can now modify this to your liking.. Have fun. Cheers!

Windows batch file: get last folder name from path

I'm trying to rename .jpg files which is in one of many subdirectories of e:\study\pubpmc\test\extracted.
I want to rename files to LastFolderName_ImageName.jpg.
(For example if Figure1.jpg is in e:\study\pubpmc\test\extracted\folder1
I want it to be renamed like this: folder1_Figure1.jpg)
So I need to take out the last folder name from the file's path.
Since it's my first time with batch scripting, I'm having a hard time.
I googled and made code similar to it
but it doesn't seem to work out.
Can you help me with it and tell me where I've done wrong?
Thank you! :)
#echo off
cd /D "e:\study\pubpmc\test\extracted"
for /r %%f in (*.jpg) do (
set mydir=%%~dpf
set mydir=%mydir:\=;%
for /f "tokens=* delims=;" %%i in (%mydir%) do call :LAST_FOLDER %%i
goto :EOF
:LAST_FOLDER
if "%1"=="" (
#echo %LAST%
goto :EOF
)
set LAST=%1
SHIFT
goto :LAST_FOLDER
)
JosefZ explains the obvious problems with your code, but he failed to point out a subtle problem, though his code fixed it:
FOR /R (as well as the simple FOR) begin iterating immediately, before it has finished scanning the disk drive. It is possible for the loop to reiterate the already named file! This would cause it to be renamed twice, giving the wrong result. The solution is to use FOR /F with command 'DIR /B', because FOR /F always processes the command to completion before iterating.
JosefZ also provides code that works for most situations. But there is a much simpler solution that works always:
#echo off
for /f "delims=" %%A in (
'dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"'
) do for %%B in ("%%A\..") do ren "%%A" "%%~nxB_%%~nxA"
The "%%A\.." treats the file name as a folder and walks up to the parent folder. So %%~nxB gives the name of the parent folder.
The command could be run as a long one liner, directly from the command line (no batch):
for /f "delims=" %A in ('dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"') do #for %B in ("%A\..") do #ren "%A" "%~nxB_%~nxA"
Avoid using :label and :: label-like comment inside (command block in parentheses). Using any of them within parentheses - including FOR and IF commands - will break their context.
Using variables inside (command block in parentheses). Read EnableDelayedExpansion: Delayed Expansion will cause variables to be expanded at execution time rather than at parse time [and CLI parses all the (command block in parentheses) at once]
Next script should work for you. Note rename statement is merely echoed for debugging purposes.
#ECHO OFF >NUL
SETLOCAL enableextensions disabledelayedexpansion
set "fromFolder=e:\study\pubpmc\test\extracted"
rem my debug setting set "fromFolder=D:\path"
for /F "tokens=*" %%f in ('dir /B /S /A:D "%fromFolder%\*.*"') do (
set "mydir=%%~ff"
set "last=%%~nxf"
call :renameJPG
)
#ENDLOCAL
goto :eof
:renameJPG
rem echo "%mydir%" "%last%"
for /f "tokens=*" %%i in ('dir /B /A:-D "%mydir%\*.jpg" 2^>nul') do (
echo ren "%mydir%\%%~nxi" "%last%_%%~nxi"
)
goto :eof
Resources:
SETLOCAL, disableDelayedExpansion, ENDLOCAL etc.
An A-Z Index of the Windows CMD command line
Windows CMD Shell Command Line Syntax
I already wrote a function for that. You give it any path and it returns you only it's filename or pathname. Works for any path: Url, Windows path, Linux path, etc...
Copy this function at the end of your batch script: (Instructions below)
rem ===========================================================================
:Name_From_Path
SetLocal
set _TMP_FOLDERNAME=%1
for %%g in ("%_TMP_FOLDERNAME%") do set _TMP_FOLDERNAME=%%~nxg
EndLocal & set _Name_From_Path=%_TMP_FOLDERNAME%
goto :EOF
rem ===========================================================================
Usage:
CALL :Name_Of_Path e:\study\pubpmc\test\extracted\folder1
ECHO %_Name_From_Path%
Result: folder1
If your program or com file traverses these folders when renaming, then it should be able to get the present working directory ( path ), pwd. You may be able to chop everything but the LAST_FOLDER out of this by also creating a PREVIOUS_FOLDER and doing a string replacement.
Or you may be able to break the folder names at the '\' token from the pwd into an array and use a -1 array reference to get the last folder name.
In any circumstance you'll want to check for a present working directory command.
If your creating a large text list of all these and issuing a single call to the batch file.
Then you may be better off with something like:
(Symmantic code warning )
(copy) /folderbase/some_folder/oneormore1/image_from_oneormore1.jpg (to) /folderbase/some_folder/oneormore1/oneormore1_image_from_oneormore1.jpg
Instead of copy, window uses rename, linux uses mv.
The latter example would require simply creating a duplicate list and replacing the \ with a _ while parsing through the tokens.
The code you've given is difficult to make sense of, so its hard to discern if you can simple concatenate the current folder and image name (stringify) and then write or rename them where they are.

Batch file that moves files when string is not in filename or when a file has finish writing

A program is writing flatfiles on a certain directory, the problem is that another program is moving the file before it finishes the writing the flatfile. i have no control on both programs i can only set the path/directory for both so i decided to create a batch file that moves the files when "~" is not in the filename. since temporary files have "~" in their filenames. can you tell me what's wrong with my program?
echo off
%%a%% = Dir /b|Find /V "~" (C:\source)
move %%a%% (C:/dest)
pause
Any suggestion wouldbe helpful
Thanks!
I tried noodles code
for /f %%A in ('dir /b^|findstr /i /v /c:"~"') do move %%A (C:\dest).
error is
the filename,directory name or volume label syntax is incorrect
im pretty sure the C:\dest exist
for /f %%A in ('dir /b^|findstr /i /v /c:"~"') do echo %%A
See for /?, dir /?, and findstr /?.
Seems to be an XY problem to me.
Sadly, your valiant attempt at a solution is more error than not.
Returning to the actual problem - we have a file being created which needs to be moved after it has been created.
The critical question would be - how do we know that creation is complete?
It is possible but not probable that the file is indeed created as a temporary file, then renamed when complete. It could be that the being-created filename contains ~ but I'd regard the assumption as highly unreliable. ~ occurs frequently in filenames, but very often in short filenames (the 'short' name for a filename that does not follow the 8.3 pattern).
The normal method for creating a file is to open it, write to it, then close it when complete. Might sound obvious, but it's also possible to re-open it and append more data then re-close it, but that would be a relatively rare approach.
In all probability, the open-write-close scenario is used by the creation application. The trick we can use in batch here is that it will appear to have a zero-length until it is closed, hence
for /f %%a in (*.*) do if %%~za neq 0 ECHO(move "%%a" "c:\dest\"
should work (note that \ is a directory-separator; / is a switch-indicator. Note also that the move command is merely echoed - remove the echo( to activate the move after verification)
If we have the open-write-close-reopen-write_again-close scenario, it becomes more complicated. What we would do then is take a directory list at intervals (say 5 sec or so) and compare it to the previous list. If the filelength of a file remains stable and >0 then that file would seem ready to transfer, if not then wait for the next dir snapshot.
Back to OP for verification/comment...
Launch this in the folder and see what the echo command writes to the console.
#ehco off
for /f "delims=" %%A in ('dir /b /a-d^|findstr /v "~" ') do echo move "%%A" "d:\folder"

Folder and file names in a spreadsheet

I was looking for a batchfile that could make a spreadsheet for all folder names at one location in 1st column and .xxx files in that folder in adjacent columns
eventually I would like to have a report that has folder name in first column and in each row corresponding .xxx file names in that folder
e.g. suppose folder_main has f1, f2, and so on and each folder has g1.xx, g2.xxx and so on
so report should show
column1 column 2 column 3 ............
f1 g1.xxx g2.xxx .....
f2 h1.xxx.......
Could you please help me to write a batch file or a script in vb to perform this function. I have thousand of folders.
Here's a starting point for you that creates a CSV-style output. You should be able to open it in any spreadsheet program.
#ECHO OFF
SETLOCAL EnableDelayedExpansion
FOR /F "delims=" %%A IN ('DIR /AD /B 2^> NUL') DO (
SET line="%%A"
FOR /F "delims=" %%B IN ('DIR %%A\*.xxx /B 2^> NUL') DO SET line=!line!,"%%B"
ECHO !line!
)
I don't know how much you know about batch-scripting, so I leave it as-is for now. However, feel free to ask if something is unclear.
EDIT:
EnableDelayedExpansion is necessary to make the !-stuff work (see below).
The first FOR-line loops over all subdirectories in the current directory and throws away all possible error messages. The stuff between the DO ( and ) in the last line gets executed for each found subdirectory.
The line-variable will hold all files once the second FOR-loop has finished. It's initialised with the name of the subdirectory, i.e. the first column in the CSV-output.
That second FOR-loop looks for all files with extension xxx in the subdirectory found in the first loop and again throws away possible error messages. The SET appends the filenames to one another.
The ! is used instead of %, which you may be familiar with. It applies the delayed expansion to the code (if you want more information about this run SET /? on your command line).
If you want to dig even deeper into the directory structure, you would need to add /S to the DIR-command in the first loop, e.g. 'DIR /AD /B /S 2^> NUL'.

Resources