How to renaming a lot of folders with a Windows batch file - windows

I need change a lot of folders with a batch script file..
I have those format of name folders:
2013.03.12.08.05.06_Debug_Test1
2013.03.12.08.04.09_Debug_Test2
...
I need change for this:
2013.12.03.08.05.06_Debug_Test1
2013.12.03.08.04.09_Debug_Test2
Invert the number 12 with the number 03
This is possible using a windows batch file?

#echo off
for /f "tokens=1,2,3*delims=." %%a in ('dir /b /ad "*.*.*.*") do if not %%b==%%c echo ren "%%a.%%b.%%c.%%d" "%%a-%%c.%%b.%%d"
for /f "tokens=1,2,3*delims=.-" %%a in ('dir /b /ad "*-*.*.*") do if not %%b==%%c echo ren "%%a-%%b.%%c.%%d" "%%a.%%b.%%c.%%d"
Should get you started.
The first FOR selects directories of the format *.*.*.* and renames them *-*.*.* with the 2nd and 3rd elements swapped.
The second renames the renamed directories to change the - to .
Consider directories 2013.03.12.08.05.06_Debug_Test1 and 2013.12.03.08.05.06_Debug_Test1 - attempting to rename the one will fail because the other exists, hence need to rename twice.
(I've assumed that '-' does not exist in your directorynames - you may wish to substitute some other character - #,#,$,q suggest themselves)
Note that I've simply ECHOed the rename. Since the second rename depends on the first, the second set wouldn't be produced until the echo is removed from the first after careful checking.
I'd suggest you create a sample subdirectory to test first, including such names as I've highlighted.

Using StringSolver, which requires a valid JRE installation and sbt, allows to use a semi-automatic version of move:
move 2013.03.12.08.05.06_Debug_Test1 2013.12.03.08.05.06_Debug_Test1
Then check the transformation:
move --explain
concatenates for all a>=0 (a 2-digit number from the substring starting at the a+1-th number ending at the end of the a+1-th AlphaNumeric token in first input + the substring starting at the 2*a+2-th token not containing 0-9a-zA-Z ending at the end of the a+3-th non-number in first input) + the first input starting at the 4th AlphaNumeric token.
which means that it decomposed the transformation by:
2013.12.03.08.05.06_Debug_Test1
AAAABBBBAABCCCCCCCCCCCCCCCCCCCC
where
A is "a 2-digit number from the substring starting at the a+1-th number ending at the end of the a+1-th AlphaNumeric token in first input"
B is "the substring starting at the 2*a+2-th token not containing 0-9a-zA-Z ending at the end of the a+3-th non-number in first input"
C is "the first input starting at the 4th AlphaNumeric token."
which corresponds to what you expected for folders of this type.
If you do not trust it, you can have a dry run:
move --test
which displays what the mapping would do on all folders.
Then perform the transformation for all folders using move --auto or the abbreviated command
move
Alternative
Using the Monitor.ps1 modified and run in Powershell -Sta, you can do it yourself in Windows like in this Youtube video.
DISCLAIMER: I am a co-author of this software developped for academic purposes.

Related

Script to move all files starting with the same 7 letters in a different folder named after first 7 chars of its future content

All files are in a directory (over 500 000 files), named in the following pattern
AR00001_1
AR00001_2
AR00001_3
AR00002_1
AR00002_2
AR00002_3
I need a script, can be both batch or unix shell that takes everything with AR00001 and moves it into a new folder that will be called AR00001, and does the same for AR00002 files etc
Here's what I've been trying to figure out until now
for f in *_*; do
DIR="$( echo ${f%.*} | tr '_' '/')"
mkdir -p "./$DIR"
mv "$f" "$DIR"
done
Thanks
// Update
Ran this in the CMD
for %F in (c:\test\*) do (md "d:\destination\%~nF"&move "%F" "d:\destination\%~nF\") >nul
Seems to be almost what I wanted, except that it does not take the first 7 characters as a substring but instead creates a folder for each file :/ I'm trying to mix it with your solutions
#echo off
setlocal enabledelayedexpansion
for %%a in (???????_*) do (
set "x=%%a"
set "x=!x:~0,7!"
md "!x!" >nul
move "!x!*" "!x!\" 2>nul
)
for every matching file do:
- get the first 7 characters
- create a folder with that name (ignore error message, if exist)
- move all files that start with those 7 characters (ignore errormessages, if files doesn't exist (already moved))
The following achieves the desired effect and checks for non-existence of the target directory each time before creating it.
#echo off
setlocal ENABLEDELAYEDEXPANSION
set "TOBASE=c:\target\"
set "MATCHFILESPEC=AR*"
for %%F in ("%MATCHFILESPEC%") do (
set "FILENAME=%%~nF"
set "TOFOLDER=%TOBASE%!FILENAME:~0,7!"
if not exist "!TOFOLDER!\" md "!TOFOLDER!"
move "%%F" "!TOFOLDER!" >nul
)
endlocal
In the move command, by moving only the current file rather than including a wildcard, we ensure that we're not eating up file names that might be about to appear the next time around the loop. Keeping it simple, assuming that efficiency is not of prime importance.
I'd recommend prototyping by creating batch files (with a .bat or .cmd extension) rather than trying to do complex tasks interactively using on one-liners. The behaviour can be different and there are more things you can do in a batch file, such as using setlocal to turn on delayed expansion of variables. It's also just a pain writing for loops using the %F interactively, only to have to remember to convert all those to %%F, %%~nF, etc. when pasting into a batch file for posterity.
One word of caution: with 500,000 files in the folder, and all of the files having very similar prefixes, if your file system has 8.3 directory naming turned on (which is often the default) it is possible to run into problems using wildcards. This happens as the 8.3 namespace gets more and more busy and there are fewer and fewer options for ways the file name can be encoded in 8 characters. (The hash table fills up and starts overflowing into unexpected file names).
One solution is to turn that feature off on the server but that may have severe implications for any legacy applications. To see what the file looks like in 8.3 naming scheme, you can do, e.g.:
dir /x /p AR*
... which might give you something like (where the left hand name is the one converted to 8.3):
ARB900~1.TST AR15467_RW322.tst
AR85E3~1.TST AR15468_RW322.tst
ARDDFE~1.TST AR15469_RW322.tst
AR1547~1.TST AR15470_RW322.tst
AR1547~2.TST AR15471_RW322.tst
...
In this example, since the first two characters seem to be maintained, there should be no conflict.
So for example if I say for %a in (AR8*) do #echo %a I get what might at first seem to be incorrect:
AR15468_RW322.tst
AR18565_RW322.tst
AR20376_RW322.tst
AR14569_RW322.tst
AR17278_RW322.tst
...
But this is actually correct; it is all the files that match AR8* in both the long file name and short file name formats.
Edit: I am aware in retrospect that this solution looks very similar to Stephan's, and I had browsed through the existing answers before starting work on my own, so I should credit him. I will try and save face by pointing out a benefit of Stephan's solution. Its use of wildcards should circumvent any 8.3 naming issue: by specifying the wildcard as ???????_*, it only catches the long file names and won't match any of the converted 8.3 file names (all of which are devoid of underscores in that position). Similarly, a wildcard such as AR?????_* would do the same.
With bash, you'd write:
for f in *; do
[[ -d $f ]] && continue # skip existing directories
prefix=${f:0:7} # substring of first 7 characters
mkdir -p "$prefix" # create the directory if it does not exist
mv "$f" "$prefix" # and move the file
done
For the substring expansion, see https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion -- this is probably the bit you're missing.

Copying files with specific extension from a list (text file) of directories

I have a text file with list of certain directories that I want to copy *.xlsx files from them to another directory.
This is how the the text file (list.txt) is arranged:
PT_NAK01, PT_NAK04, PT_NAK05, PT_JAR03
What I have so far:
#echo off
set main_folder="\\internal.company.com\project folder\"
set my_folder="C:\_M__\files"
for /f "tokens=*" %%i in (list.txt) DO (
xcopy "%main_folder%\%%i" "%my_folder%"
)
So the folders that I want to look into would be \\internal.company.com\project folder\PT_NAK01 etc.
What I don't know is how to pass the specific extension *.xlsx to this command.
Note: I haven't used /S switch with xcopy deliberately because I do not want the files in the sub-directories.
P.S. Solutions in powershell or cygwin work for me as well.
This is a cygwinshell answer (bash is an advanced shell that should be reserved for when standard Posix shell (/bin/sh) is insufficient). Note that slashes are reversed intentionally.
I see the format in your list.txt is delimited with commas and whitespace. I am going to assume that this is literal and the reason none of what you've tried so far works. Therefore, I am parsing it with the explicit assumption that comma and then space (, ) is a delimiter and that there is no way to escape them (e.g. if you have a file named apples, oranges.txt then my code would erroneously parse files named apples and oranges.txt).
#!/bin/sh
main_folder="${1:-//internal.company.com/project folder}"
my_folder="${2:-c:/_Masoud/files}"
cd "$main_folder" || exit $?
IFS=', ' find $(cat list.txt) -maxdepth 1 -name \*.xlsx |while IFS= read xlsx; do
mkdir -p "$my_folder/${xlsx%/*}"
cp -a "$xlsx" "$my_folder/$xlsx"
done
I've done some extra work for you to make this more abstract. $main_folder is taken from your first argument (a missing argument will default to //internal.company.com/project folder) and $my_folder is taken from your second argument (if missing, it defaults to c:/_Masoud/files). Don't forget to quote your command-line arguments if they contain spaces or interpretable characters.
After determining your source and destination, I then try to change directories to the source directory. If this fails, the script will stop with the same exit code.
Now for the loop. I've changed the Input Field Separator ($IFS) to be the comma and space (, ) we talked about earlier and then glued the contents of list.txt into its arguments, followed by the requirement of being one level deep (to include PT_NAK05/foobar/baz.xlsx, use -maxdepth 2 or just remove that clause altogether to view the file tree recursively), followed by the requirement of a name matching *.xlsx (this is escaped because your shell would otherwise assume you're talking about the local directory). The output of this is then read into a loop line by line as $xlsx. We recreate the target's parent directory in the new target destination if it's not already present, then we copy the file to that location. cp -a preserves permissions and time stamps.
One thing that made an error in my example was how I set the text file with the folder names. It should be set up with carriage return as separator instead of comma-separated entries.
PT_NAK01
PT_NAK04
PT_NAK05
etc.
With that, this batch-file (in reference to MatSnow's and shellter's comments) works fine for the purpose of the question.
#echo off
set main_folder="\\internal.company.com\project folder\"
set my_folder="C:\_M__\files"
for /f "tokens=*" %%i in (list.txt) DO (
xcopy "%main_folder%\%%i\*.xlsx" "%my_folder%"
)
Note: If you want to type this directly into the command line, you don't need double % for the variables.

Windows delete with wildcards deleting erratically

This is driving me crazy. Basically, I have a program that outputs tables to a flat file for multiple databases with the same structure. These files get named in the format tablename_####.dat, where #### is the 4 digit company number. After these are all created, the program then combines all of the files by tablename, and adds a timestamp on the end. So, the final file name is in the format tablename_YYYYMMDD_HHmmSS.dat. Finally, I want to delete all of the individual .dat files, leaving only the combined, time stamped files.
This works just fine for all of the tables, except for the table VEX. For example, I have files:
VEX_1234.dat
VEX_5678.dat
VEX_0987.dat
which combine to form VEX_20150414_144352.dat. After this, I run the command:
`del *_????.dat`
This deletes all of the tables' individual files (V_1234.dat, PAT_9534.dat, etc.), while leaving the combined files (V_20150414_142311.dat, PAT_20150413_132113.dat) ...except for VEX. It deletes both the individual files and the combined file. Shouldn't this only delete files that end with an underscore, 4 characters, and ".dat"?
I know this has to be something really simple that I'm missing. What is going on?
Most likely your issue is caused by short 8.3 file names.
The ? wildcard can match 0 or 1 character if it precedes a dot. Your file mask of *_????.dat will match any name that has any number of characters, followed by a _, followed by 0 to 4 characters, followed by the .dat extension. The tricky thing is it will attempt to match both the long file name, and any short 8.3 name, if it exists.
Try issuing dir /x *.dat, and look at the short name of the problem file. I suspect it will match your file mask.
There are patterns with how short names are derived, but there is no way to predict the short name of any given file unless you are aware of all existing short names within the folder, and then you would be relying on undocumented behavior.
This is a fairly common problem. If your files are on an NTFS drive and you have admin rights, then you can disable short file name generation. But this does not remove already existing short names.
The best general solution is to pipe DIR /B through FINDSTR to remove the unwanted files, and process the result with FOR /F to delete each file individually. The FINDSTR below will exclude file names that contain two or more _ characters.
for /f "delims=" %%F in ('dir /b *.dat^|findstr /v "_.*_"') do del "%%F"

get an unknown string between two strings and save it in a var (Windows script)

The thing is that I want to do this JUST by using Windows bash utils (so it can be easily used without other applications like Cygwin/grep on other workstations).
Also this command will be in a larger script that uses the extracted string as a part of a filename.
ex: this is the line in the searched file
" <DataVersion>A0C2</DataVersion>"
A0C2 is the string that I need but it can have a different value like X1Z4 but is always 4 alfanumeric characters long.
<DataVersion> and </DataVersion> are always present.
Also the line may occur more than once but I only need the first to be considered.
I found out in the mean time the answer to my own question.
set ROW=
set VERSION=
for /f %%i in ( 'findstr "<DataVersion>" file.txt' ) do #set ROW=%%i
set VERSION=%ROW:~x,y%
where:
x is the number of characters you want to skip in ROW and
y is the number of characters you want to save in VERSION
so in case
findstr "<DataVersion>" file.txt
returns and sets ROW to this value:
<DataVersion>AX23</DataVersion>
then:
set VERSION=%ROW:~14,4%
will set VERSION to AX23

Word Sorting in Batch

Right let me rewrite this try to make it more clear.
Picture added to make this even clearer:
I have two files
File 1, contains words.
file 2, contains commands.
I need to put words from FILE 1
into FILE 2
I cannot copy-paste them one by one, because there is a LOT of words in FILE 1
File 1 is listed in alphabetical order (by first letter)
File 2 the command does not change
The issue is getting words from file 1 into file 2
but they have to be moved into quotes " " in file 2
so a script that could for example..
Take apple from file 1 and move it between quotes admin.executemotecommand "apple"inside file 2 as it goes down the list keeping the words in order as they move them across.
This could perhaps be done the same way around in which, the script writes the command in front of the words in file 1 as it goes down file 1's list
Is this even possible? I've never seen this done anywhere else and completely clueless if batch is even the right language for it.
The question is a little confusing, but based on your responses in the comments my understanding is that you don't necessarily need the script to edit a preexisting file 2, because you're repeating the same command(s) for each word, so the script can just create a new file based on the words in file 1.
You can do it at the prompt like this:
FOR /F %a IN (words.txt) DO ECHO admin.executeremotecommand "%a" >> commands.txt
The original version of the question indicated that you want more than one command for each word. I take it you changed that in order to simplify that question, and figured you'd just run the script once for each command? However, it's quite simple to have it produce more than one command for each word:
FOR /F %a IN (words.txt) DO (ECHO first.command "%a" & ECHO second.command "%a") >> commands.txt
In a batch file, you'd do it this way:
#ECHO OFF
FOR /F %%a IN (words.txt) DO (
ECHO first.command "%%a"
ECHO second.command "%%a"
) >> commands.txt
BTW, in the code in some of your comments, you surrounded the variable with %'s (%A%). That's incorrect; it would evaluate to the value of %A followed by a literal %. Surrounding with %'s is used only for environment variables. (Note that the %'s around environment variables do not get doubled in a batch file. For example, to get the current date, use ECHO %date% both at the prompt and in a batch file.)

Resources