Have 2,000 files, each with 51-62 character-long filenames. For each filename, I would like to add the character-stretch in position 14-23 to the very beginning of the filename. (Filename character types and patterns are variable, so the rename must be based on position counting from the filename's beginning.)
Windows 7, command prompt FCIV solution preferred.
For example:
original:
abcdefghijklmNo0123456p8901234567890.ext
new:
No0123456pabcdefghijklmNo0123456p8901234567890.ext
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\folder"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*" '
) DO (
SET "name=%%a"
CALL :transform
)
GOTO :EOF
:transform
ECHO REN "%sourcedir%\%name%" "%name:~13,10%%name%"
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.
The variable sourcedir is set to point to the directory of interest. By setting a variable, the directoryname can be changed in one place rather than editing it in multiple places should it be used in multiple places. The set "var=value" syntax ensures any trailing spaces on the line are not included in the value assigned.
The dir command produces a list of filenames in the target directory /b means "filenames only - no header/trailer lines, no date, time size - just the filename" /a-d means "and no directory names"
This list is built in memory, and then read line-by-line by the for/f. The "delims=" ensure that the entire line is applied to the metavariable %%a so that filenames that include default separators are not truncated. Each filename is then assigned to the variable name because substringing can't be applied directly to a metavariable. The subroutine :transform is then executed.
The subroutine is quite simple - all it does is echo a rename command, using the full filename built from the variables sourcedir and name. The syntax of the ren command requires that the new name is name-only, the subdirectory is implicit. The new name is built from the substring within name starting at character 13 (the first character is character 0) for a length of 10 characters + the original name.
Since the dir list is built in memory before the for starts executing, the names delivered to the for are the original names. If a file has become renamed, it will not be re-processed as its new name is not in that original list.
The idea of ECHOing the ren line is so that the user can see whether the ren commands generated are correct. All that happens is that a report is sent to the screen. If it is then determined that the result appears correct, then changing echo ren to ren will actually execute the rename rather than reporting it. That's a decision to be made by the user. If the resultant ren is wrong (wrong count of position or length, or wrong directory or whatever) then no harm is done as the product is simply a report until the job is run with echo ren changed to ren.
Related
I want to write a batch program to copy some deeply nested folders with the same suffix in this case 100,
It only copied all the folders but only one file in the top most folder (they are alphabetically arranged in the server) *100.bat was copied.
I want to copy all files in all folders with name_of_folder100.
Thanks for your Time.
This is my attempt:
#echo off
:: variables
set hour=%time:~0,2%
if "%hour:~0,1%"==" " set hour=0%time:~1,1%
set
set drive= E:\PWD_BACKUP_%date:~10,4%_%date:~4,2%_%date:~7,2%_%hour%_%time:~3,2%
set PWD_drive_100=E:\PWD_BACKUP_\PWD_100_%date:~10,4%_%date:~4,2%_%date:~7,2%_%hour%_%time:~3,2%
set backupcmd=xcopy /s /c /d /e /h /i /r /y
%backupcmd% "\\xx.xx.xx.xx\live_projects\PWD\*100" %PWD_drive_100%
It's normal to follow the #echo off line with setlocal. This makes sure that any variables altered or created in the batch file are not maintained in the cmd session's environment when the batch ends.
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign a terminal \, Space or " - build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.
The set drive=... statement will include the space following the = in the value assigned to drive. This is probably of no consequence in the current situation, but may be significant for other batches.
Other than the last 2 lines of code, there is a great deal of date/time-manipulation going on. We have to rely on your local knowledge here as the date/time format is user-dependent.
The overall problem is that * cannot be used for directorynames. Logically, what you appear to want to copy from your description is ...e_projects\PWD\*100\*, but that structure is not supported by xcopy.
So I'll restate the problem as "copy all directories that have a name ending 100"
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the directories and filenames are names
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
FOR /f "delims=" %%e IN (
'dir /b /s /ad "%sourcedir%\PWD\*" ^|findstr /e "100"'
) DO (
SET "dirname=%%e"
SET "dirname=!dirname:*\PWD\=!"
ECHO XCOPY "%%e\*" "%destdir%\!dirname!\"
)
GOTO :EOF
Always verify against a test directory before applying to real data.
The setlocal enabledelayedexpansion invokes delayedexpansion mode, where within a code block (parenthesised sequence of lines) !var! is the run-time value of var (as var is changed) and %var% is the value that var contained when the code block was parsed.
Documentation: Stephan's DELAYEDEXPANSION link
We then establish the source and destination directories. I've posted my test directories, you would need to edit them to suit your particular circumstances.
The dir command lists all directories (/ad) in basic form (/b) that is, name only - no size, date, etc. The /s extends the scan to subdirectories also.
The dir output is piped to findstr (the caret escapes the pipe to show that it is part of the command to be executed, not of the for) which filters the dir list for (directorynames) which /e end "100".
The for/f assigns each line of the result to %%e. The delims=" ensures the entire line is assigned to %%e(in case%%e` contains separators like Space)
%%e thus contains something like U:\your files\PWD\sub 5\subsub 5\subsubsub\subsubsubsub100, so we need to remove the part up to \PWD\ to get the subdirectory name in a format suitable for the xcopy command. Batch cannot substring a metavariable like %%e directly, so we assign %%e to a user-variable dirname (which is therefore changing within the loop, so we need to use !dirname! to acess it's run-time value) and the following set removes all characters up to and including \PWD\. (See set /? from the prompt for documentation)
Then it's just a matter of performing the xcopy. Note that I've added an echo keyword to "disarm" the xcopy so that the xcopy command is merely listed to the console instead of being executed. Once you've verified that the command is correct, remove that echo to actually execute the xcopy.
The destination of the xcopy is </kbd> which tells xcopy that the destination is a directory, and to create it if it does not exist.
Add >nul to the xcopy command to suppress the report if you want.
everything in my code is working fine except the last part.
I am wanting to output each text file to the folder with the same name. It is outputing the three text files into the one folder PentahoOutputs. However I am wanting to output it as the following:
folder system2.object2.assets contains file system2.object2.assets
folder system3.object3.assets contains file system3.object3.assets
folder system4.object4.assets contains file system4.object4.assets
#echo off SetLocal EnableDelayedExpansion
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC = C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( SET subdirs=%%a
result=!subdirs:~71,7!
result2=!subdirs:~79,7!
set "concats=!result!!delims!!result2!!DELIMS!!COMMAND!!DELIMS!!EN!"
echo !concats!
echo !CONCATS! >>C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\!result!!delims2!!result2!!delims2!!assets!.CSV
)
PAUSE>NUL
edit ********** below
changing the problem code to the following puts each of the three files in each of the three folders... however i want one file in each folder
for /d %%b in (C:\Users\usre.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( echo !CONCATS! >>%%b\!result!!delims2!!result2!!delims2!!assets!.csv )
From your posted code - given aschipfl's change as noted (although you don't attempt to use direc)
Your posted code has been mangled in an attempt, I assume, to disguise usernames. It also appears that you've cut down the actual code to show only the relevant section. This is good and understandable (but your edit has a glaring typo in the code - which is why you should cut-and-paste as far as possible.)
So - the setlocal following the #echo off must be separated by a & command-concatenator or be (my preference) on a separate line.
Within your for ... %%a ... block, you've removed the required set keyword for result*.
The fixed values you've used for substringing don't suit the changes you've made to the pathname, so the result in result is (eg) "tem3.ob"
If a value does not change within a block (like delims) then it's probably best to use %delims% - result changes, so you'd use !result! not %result%. !delims! also works, of course - but using the delayed-expansion form primes the reader to believe it's going to vary. (opinion)
'tis best with a string assignment to use set "var=value" as the quotes ensure that stray trailing spaces are not included in the value assigned. You only ever need to have that happen once...
OK - here's a revision
#echo OFF
SetLocal
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC=U:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (%direc%*) DO (
FOR /f "tokens=1,2,3 delims=." %%p IN ("%%~nxa") DO IF /i "%%r"=="%assets%" (
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN%
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN% >> %%a\%%~na.CSV
)
)
GOTO :EOF
Note that I've used U: for the test directory (it's a ramdrive on my machine)
Given the outer loop, %%a is assigned the full pathname to the directory.
Since you imply that your target directorynames are system2.object2.assets then %%~nxa (the Name and eXtension of %%a) conveniently holds this string. Parsing that using delims of . and selecting the first 3 tokens would assign system2 to %%p, object2 to %%q and assets to %%r This avoids the substringing problem and permits system and object to be any length - not just 7.
The if statement ensures that the main block for for...%%p is only executed for directories found which fit ..asset (/i makes the if case-insensitive)
The required line can then be constructed from the metavariables and constants, as can the destination filename, so the enabledelayedexpansion is not required.
I am moving files based on their names to preset folders. I don't want to make new folders. So files should only be moved if the corresponding folder is existing already.
The file names all follow the same pattern: 1234_123456_AA_***********.(doc/pdf)
I have the following script below which works:
#echo on
for /r %%f in (*.*) do (
echo processing "%%f"
for /f "tokens=1-3 delims=_" %%a in ("%%~nxf") do (
move "%%f" C:\Users\xxxxxxxxx\Desktop\MOVEFILES\%%a_%%b_%%c\
)
)
pause
But the issue I am running into is that some of the files names have a '0' place holder in loop variable %%b, for example 1234_0123456_AA. But this file name should be interpreted like 1234_123456_AA and I want this file moved into the appropriate folder.
I have written this:
#echo on
SETLOCAL ENABLEDELAYEDEXPANSION
for /r %%f in (*.*) do (
for /f "tokens=1-3 delims=_" %%a in ("%%~nxf") do (
set z=%%b%
echo !z:~-6!
move "%%f" C:\Users\xxxxxxxxx\Desktop\MOVEFILES\%%a_%%z_%%c\
)
)
pause
I get the echo to remove the '0' place holder, but need to get that back into %%b in the file path of where the file should be moved to.
What to modify in code to get the desired behavior?
Use the following code with the corrections of JosefZ applied and some additional improvements:
#echo off
setlocal EnableDelayedExpansion
for /R %%F in (*_*_*.*) do (
for /F "tokens=1-3 delims=_" %%A in ("%%~nxF") do (
set "MiddlePart=%%B"
set "MiddlePart=!MiddlePart:~-6!"
if exist "%USERPROFILE%\Desktop\MOVEFILES\%%A_!MiddlePart!_%%C\*" (
move /Y "%%F" "%USERPROFILE%\Desktop\MOVEFILES\%%A_!MiddlePart!_%%C"
)
)
)
endlocal
pause
The improvements on code are explained below in details.
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.
echo /?
endlocal /?
if /?
move /?
set /?
setlocal /?
1. Search pattern
The first improvement is the pattern used in first FOR as only files should be moved with at least 2 underscores in file name. This pattern is still not the best one, but good enough for this task.
2. Loop variable
It is better to use loop variables in upper case to avoid problems with the modifiers.
For example using as loop variable %%f and using inside the loop %%~f to use the string (must not be a file or folder name) of loop variable f without surrounding quotes, command processor exits batch processing with an error message because it expects one more letter, the loop variable as %%~f is interpreted as full name of file/folder of loop variable ?.
The loop variables and the modifiers are case sensitive. Therefore %%~F is interpreted by command processor as string of loop variable F without surrounding quotes and %%~fF as file/folder name with full path and extension of the file/folder of loop variable F.
Some other characters like # can be also used as loop variable.
3. Assigning value to environment variable with quotes
On assigning a string to an environment variable, it is always good to use
set "variable=text or other variable"
Using the quotes as shown here has the advantage that not visible spaces/tabs after last double quote are ignored by command processor.
But with using just
set variable=text or other variable
everything after first equal sign up to line termination is assigned to the variable including trailing spaces and tabs added perhaps by mistake on this line in the batch file. This is nearly never good and a common source of a batch execution problem which can be easily avoided by using quotes right.
Using the quotes as show below is also not good as in this case both double quotes are part of the text assigned to the variable (plus trailing spaces/tabs). This is sometimes useful, but is most often a coding mistake.
set variable="text or other variable"
4. Delayed expansion
Referencing a variable set or modified within a block defined with (...) requires delayed expansion if the current variable value should be used and not the value assigned to the variable above the block. Therefore using %%z was wrong in original code as variable z was not defined above first FOR loop and therefore was replaced always with nothing on execution of the loops.
5. Environment variable USERPROFILE
Running in a command prompt window set results in getting displayed all predefined environment variables for the current user account. There is the variable USERNAME, but also USERPROFILE containing path to the userĀ“s profile directory with the Desktop folder and other user account related folders. Using environment variable USERPROFILE makes the batch file less dependent on Windows version and language of Windows.
ATTENTION:
The first FOR runs because of /R recursive on current directory and all its subdirectories. As the inner FOR loop moves all found files in current directory tree to subdirectories of %USERPROFILE%\Desktop\MOVEFILES, the current directory should be never any directory of this path.
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.
Can someone help me with a batch script. I need a script, who can remove last word and space in file name or directory.
For example:
New folder to be after execution of script New - remove last space and word.
this should work ren *" "* *" ". Be careful though since this is going to change everything in that directory. If you know the 1st word of the file or folder then you can use this ren 1stword" "* *" ".
#ECHO OFF
SETLOCAL enabledelayedexpansion
FOR %%t IN (*) DO (
CALL :process "%%~nt"
IF DEFINED success ECHO REN "%%t" "!success!%%~xt"
)
GOTO :eof
:process
SET "success=%~1"
:procloop
SET "lastchar=%success:~-1%"
SET "success=%success:~0,-1%"
IF NOT DEFINED success GOTO :EOF
IF NOT "%lastchar%"==" " GOTO procloop
:: Remove any other trailing spaces
:rtsloop
SET "lastchar=%success:~-1%"
SET "success=%success:~0,-1%"
IF "%lastchar%"==" " GOTO rtsloop
SET "success=%success%%lastchar%"
GOTO :eof
This should do the trick for most "normal" names. It will possibly fail for names containing a very few characters like ! and ^ - but such file/directorynames are silly.
Change the FOR to a FOR /d to process directories, not files.
Essentially, the NAME part of the ...name is passed to the :process routine in quotes to preserve its spacing, and the routine first lops off the final character until it finds a space, then continues removing any further spaces.
If the name has no spaces, success will be empty and therefore undefined, otherwise it'll have the new name.
After verification, change the ECHO REN to simply REN to do the renaming, this routine simply REPORTS what it intends to do.
Addendum:
We have a little terminological conundrum.
For FILES, FILENAME.TXT if often called the "name" of the file, but FILENAME is the "name" and .TXT is the EXTENSION.
When this process is occurring, the desired outcome is that FILENAME WITH SPACES.EXT becomes FILENAME WITH.EXT to preserve the EXTENSION or TYPE of the file.
With DIRECTORY names, the idea of an "EXTENSION" is still supported, so Folder 18.9.0.17 is regarded as Folder 18.9.0 with an extension of .17 (the extension is whatever occurs after the final .)
The cure is quite simple - don't add the extension in the rename.
IF DEFINED success ECHO REN "%%t" "!success!"
(but note that Folder 18.9.0.17, Folder 18.9.0.18, Folder 18.9.0.19 will ALL have a target rename of Folder here - only the first may succeed...)