Folder and file names in a spreadsheet - batch-file

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'.

Related

How to remove digits from beginning of filename?

I need to rename a filename like this 7612372 filename 50x50.jpg into this filename 50x50.jpg, removing all digits at the beginning of the filename.
The number of digit can be variable.
I need to integrate this into an existing batch file run from the Windows command prompt.
If the format of the filename would be the same for all the files in the folder, then you can try:
#echo off
for /F "delims=" %%A IN ('dir /b /A-D') do (
for /F "tokens=2-3" %%B IN ("%%A") do (
ren "%%~fA" "%%B %%C"
)
)
This is the shortest way, but not the most accurate one. It is unsecure, because if the filename contains spaces, the file will be rename incorrectly. I suggest the following code for the task:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%A IN ('dir /b /A-D') do (
set filename=%%A
for /F "tokens=1" %%B IN ("%%A") do (
ren "%%~fA" "!filename:%%B =!"
)
)
which is more accurate and renames all files correctly only if they have the format mentioned in the beginning.
#echo off turns command-echoing off.
setlocal EnableDelayedExpansion enables delayed expansion. We use it only here, as we have to access variables inside a for loop which is a code block. You must use delayed expansion always inside these code blocks.
Now we make a for loop to parse the output (/F) of the dir /b /A-D command which lists all items in current working directory (%cd%), excluding directories (/A-D).
We need to set a variable here with the filename. We could use the variable name of the loop (%%A), but variables have an advantage: %var:search=replace%, or even !var:search=replace! which we need here.
Now we make another for loop to parse a string (/F): the filename (%%A). We need to access the first token to substract it later. We don't really need to specify it here, but it is good to make it clearer.
We rename files now: %%~fA is the full path where filename currently processed is and !filename:%%B =! means to take filename environment variable, search for string "%%B " (first part of filename [digits] and a space) and replace it with an empty string; actually nothing!
An easier solution is to use
all digits and space as delims and
tokens=*
:: Q:\Test\2019\01\06\SO_54054587.cmd
for /F "delims=" %%A in (
'dir "* *" /A-D-H /B 2^>nul'
) do for /F "tokens=* delims=0123456789 " %%B in (
"%%A"
) do ren "%%A" "%%B"
this will remove all leading delimiters while not splitting the remainder of the file name.
Like the other answers this will not account for the shorted file name already being present.
Your question is not specific enough for us to provide a solution, you really need to provide the section of code into which you wish this to be integrated.
This one expects only one file, as in your question, and that file must be named in the format you've indicated, i.e. the required part is separated from the non-required part by a space:
#Set "name=7612372 filename 50x50.jpg"
#Ren "%name%" "%name:* =%"
[Edit /]
I have noted from your comments that you were indeed looking to parse several files and those files did not match the naming scheme you provided in your question.
Here therefore is an updated potential solution based on those changed parameters.
#For %%A In (*.*) Do #For /F "Tokens=* Delims=0123456789 " %%B In ("%%A") Do #Ren "%%~A" "%%B"
Apologies to LotPings, who I've noticed has posted a very similar method/solution
It's very simple with the basic DOS command rename.
7612372 filename 50x50.jpg
If this is your sample file in the folder, it contains 7 digits and 1 blank space. Totally 8 characters.
We can do this by simply running this command on the particular folder
rename "*.mp3" "////////*.mp3"
each / represents a character you want to remove. That's it.
I suggest following batch code for this task:
#echo off
for /F "delims=" %%A in ('dir "* *" /A-D-H /B 2^>nul') do for /F "tokens=1*" %%B in ("%%A") do ren "%%A" "%%C"
pause
The command FOR runs with cmd.exe /C (more precise %ComSpec% /C) in a separate command process in background the command line:
dir "* *" /A-D-H /B 2>nul
DIR outputs to handle STDOUT of this background command process
just the names of all non-hidden files because of option /A-D-H (attribute not directory and not hidden)
in bare format because of option /B without file path
matching the wildcard pattern * * which matches any file name with at least one space inside
in current directory which can but must not be the directory of the batch file.
DIR would output an error message to handle STDERR if it can't find any directory entry matching these criteria. This error message is redirected to device NUL to suppress it.
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR captures all lines output to handle STDOUT of started command process and processes those lines after started cmd.exe terminated itself. It is very important for this file renaming task that FOR runs on a list of file names captured before doing the file renames as otherwise the directory entries would change while FOR is accessing them. For that reason for can't be used directly in this case because of for would process the list of * * directory entries while this list changes on each successful file rename. The result would be files not renamed or renamed multiple times or even an endless running loop depending on file system (NTFS or a FAT file system like FAT32 or ExFAT).
FOR with option /F ignores empty lines which do not occur here. FOR ignores also lines starting with a semicolon because of end of line option eol=; is the default. But all lines output by DIR should start with a number and for that reason the default end of line definition can be kept for this task.
FOR with option /F splits up a line by default to substrings using normal space and horizontal tab as delimiters and assigns just first space/tab separated string to specified loop variable. This line splitting behavior is not wanted here in outer FOR loop because loop variable A should hold complete file name with all spaces. Therefore delims= is used to define an empty list of delimiters to disable the line splitting behavior. Safer would be "delims= eol=" which defines also no end of line character.
The file name assigned to loop variable A is referenced with %%A as string in inner FOR loop which splits up the file name into two substrings (tokens). The first substring is the number assigned to specified loop variable B. The second substring after first sequence of spaces (tabs not possible in a file name) is assigned without any further splitting to next loop variable C according to ASCII table. In other words on file name 7612372 filename 50x50.jpg loop variable B holds 7612372 and filename 50x50.jpg is assigned to loop variable C.
The command REN renames the file by referencing complete file name as assigned to loop variable A to the part after first sequence of spaces as assigned to loop variable C.
The command PAUSE at end is added to see the error message output by command REN if renaming a file failed. There is nothing output except the prompt by PAUSE on all files could be renamed successfully.
The batch code can be enhanced further by using FINDSTR as filter to make sure that a file to rename starts really with one or more digits up to first space by using this code:
#echo off
for /F "delims=" %%A in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /C:"^[0123456789][0123456789]* "') do for /F "tokens=1*" %%B in ("%%A") do ren "%%A" "%%C"
pause
One more variant for renaming a file with name 03T30 NAME T ALL 40X40X2 - Copy.JPG to T30 NAME T ALL 40X40X2 - Copy.JPG:
#echo off
for /F "delims=" %%A in ('dir /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]*"') do for /F "tokens=* delims=0123456789 " %%B in ("%%A") do ren "%%A" "%%B"
pause
DIR outputs the names of all non-hidden files in current directory. This output is redirected as input for FINDSTR which checks if the file name starts with one or more digits. Only those file names are output to STDOUT of background command process to be processed next by FOR.
The inner FOR interprets all digits and space character as string delimiters because of delims=0123456789  and assigns everything after first sequence of digits or spaces to loop variable B because of tokens=*. So loop variable B holds filename 50x50.jpg with 7612372 filename 50x50.jpg assigned to A and T30 NAME T ALL 40X40X2 - Copy.JPG for file name 03T30 NAME T ALL 40X40X2 - Copy.JPG.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
findstr /?
for /?
pause /?
ren /?
PS: I recommend the usage of the shareware file manager Total Commander which has a built-in multi-rename tool for renaming files and folders for people with no coding experience. Download, install and start Total Commander, navigate to the folder containing all these files, press Ctrl+A to select the files, press Ctrl+M to open multi-rename tool window and the rest is self-explaining. If you need nevertheless help, press key F1 to open the help page for multi-rename tool.

Batch script to remove "duplicate" files

I have a list of files named:
file.txt
file (1).txt
file (2).txt
etc.
Where the greater (number) is the last file updated.
I want a .bat script that allows get the content of file (maxnumer).txt to file.txt.
dir /B /OD /TW file*.txt lists file names in sort order of last written time (cf. dir /?).
Next commented batch script could do the job for you:
#echo OFF
SETLOCAL EnableExtensions
rem delete empty `_lastfile` variable
set "_lastfile="
rem store file name of last written time into `_lastfile` variable
for /F "delims=" %%G in ('dir /B /OD /TW file*.txt 2^>NUL') do set "_lastfile=%%~G"
rem ↑↑↑↑↑↑ suppress errors
rem check the `_lastfile` variable
rem is defined?
rem AND is different from "file.txt"?
if defined _lastfile if /I "%_lastfile%" NEQ "file.txt" copy /Y "%_lastfile%" "file.txt"
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~G etc. special page) Command Line arguments (Parameters)
(2>NUL etc. special page) Redirection
Here is a bit of a hacky answer.
This script will move all files from file (1).txt up to file (10).txt to file.txt , leaving only file.txt which now contains the text that was in file (10).txt
Doing it in ascending order will ensure the highest number that exists is the last one to be moved.
#echo off
set /P name=Enter name of file without extension:
echo enter extension:
set /P ext=.
echo. & echo.
echo these actions will be performed: & echo.
FOR /L %%A IN (1,1,10) DO #echo move /y "%name% (%%A).%ext%" "%name%.%ext%"
echo. & pause & echo.
FOR /L %%A IN (1,1,10) DO move /y "%name% (%%A).%ext%" "%name%.%ext%"
pause
You could use IF EXIST %name% (%%A).%ext% To stop the script from trying to move files that don't exist, but it doesn't really affect anything to do that, so I didn't bother.
The script above will do it for a specific named file. To do it for all files in a directory will be possible, here are some hints to get you going
use a dir /b >filenames.txt to get all files in a directory listed in a text file
to perform an action for every line in a textfile do
for /f "usebackq delims= tokens=* %%a in (`filenames.txt`)" DO (
::some stuff here
)
The way I would go about it would be to get filenames.txt , manually delete all the (n) files so you just have a list of the "non-duplicate" filenames, and use that as your input. You
There are probably more elegant solutions out there, but with all the peculiarities of batch I wouldn't be surprised to find they are pages and pages long.
If you want to keep all the original files not just end up with the final file.txt with no copies, then I you want to use COPY
If you want to keep all the original files, then you would want to use COPY not MOVE.
In that case, to remove all superfluous operations (i.e. only copy the highest numbered file, not copy all the files in order) then something like IF NOT EXIST %name% (!B!).%ext% where !B!=%%A+1 within your (now multiline) for loop and use Setlocal EnableDelayedExpansion on to make the arithmetic work properly. But it's not really necessary, copying 1, then 2, then 3, then 4 does the same thing if a little slower than skipping 1 2 and 3 and just doing 4.
I hope this helps enough to point you in the right direction, feel free to ask questions if this isn't clear.

Renaming BAT suddenly not working correctly

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.

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"

batch file script to backup old increment of multiple files and change the last increment to "1"

First of all, I am completely newbie here in batch file scripting and willing to learn it.
Let's say that I have a bunch of files in a folder with file extension/file-ext: ext1, ext2, and ext3.
every single file has incrementation such as:
filename.file-ext.1
filename.file-ext.2
filename.file-ext.3
...
filename.file-ext.x
The main target is to backup the old increments(from 1 to x-1), then backup them in a new folder, and then change the last increment "x" to "1".
Any kind of help from you would be highly appreciated.
The main problem when file names contain numbers is that they appear in alphabetic, not numeric, order. For example:
filename.file-ext.1
filename.file-ext.10
filename.file-ext.11
filename.file-ext.12
filename.file-ext.2
filename.file-ext.3
filename.file-ext.4
filename.file-ext.5
filename.file-ext.6
filename.file-ext.7
filename.file-ext.8
filename.file-ext.9
The last file in previous list should be 12, but the last name given by for or dir commands is 9. The Batch file below uses a two-pass approach: it first review the whole list and get the real last numeric file, then it process the list again and backup all files excepting the last one.
#echo off
setlocal EnableDelayedExpansion
rem First pass: Get the last numeric file
set last=0
for %%a in (filename.ext.*) do (
set num=%%~Xa
if !num:~1! gtr !last! set last=!num:~1!
)
rem Second pass: Backup all files excepting the last one
for %%a in (filename.ext.*) do (
if %%a neq filename.ext.%last% move %%a \backupDir
)
rem Rename the last file, if it is not 1
if %last% gtr 1 ren filename.ext.%last% filename.ext.1
The program above was written as simplest and clearest as possible. You must insert some quotes if file names may have spaces.
#ECHO OFF
SETLOCAL
SET filename=FILENAME
SET fileext=FILE-EXT
SET "deedpoll="
FOR /f "delims=" %%i IN ('dir /b /a-d /o:-d "%filename%.%fileext%*"') DO (
IF DEFINED deedpoll ECHO MOVE "%%i" "\newdir\" >nul
IF NOT DEFINED deedpoll SET "deedpoll=%%i"
)
IF DEFINED deedpoll ECHO REN "%deedpoll%" "%filename%.%fileext% 1"
since we have no clue as to the real filename or file extension involved, we can only assume that they will be simple alphamerics and spaces. I've also assumed that your destination directory exists and that your current directory is the one containing your fileset.
And I've assumed that your sequencing will work on DATE - it's the NEWEST file that does NOT get backed up (moved to newdir) and renamed ...1
It's quite simple. First clear deedpoll then perform a dir listing of the /b bare filename, /a-d with no directorynames /o:-d in reverse-order of date.
The first filename assigned to %%i will thus be the newest. deedpoll is not yet set, so the move is not executed, and then deedpoll is assigned the name of the newest file.
Since deedpoll is now set (or defined) then the move will be done for each of the other filenames matching the supplied mask.
finally, deedpoll is renamed to version 1.
Note that the REName and MOVE commands are merely ECHOed to the screen. This is to allow you to ensure that the batch would do what you want it to do. If all is correct, remove both of these ECHO keywords to activate the rename and move.

Resources