Windows x64 & "parenthesis in path" batch file problem - windows

Windows x64 versions contain folders named with parenthesis like "\Program Files (x86)" and this breaks a batch file I use. An example of a problem line:
for %%c in (%path%) do if exist "%%c\xyz.exe" set xyz=OK
i.e. when it reaches ")" in "(x86)" it puts out an error message and exits...
Any ideas on how to fix this?
This is a rather large batch file, and atm I don't have the time to rewrite it in a better language...
Many thanks :)

Doesn't directly answer your question, but if you are trying to do what I thinking you are trying (which is make sure a file exists in the path) you can use something like the following in a batch file.
#echo off
for %%i in (xyz.exe) do set xyz=%%~$PATH:i
if "%xyz%" == "" Goto NotFound
Echo "Found"
Goto TheEnd
:NotFound
Echo "Not found"
:TheEnd

Normally quoting should work, but in this case you want to iterate over all elements seperated by ;.
But you can replace the ; to a " " combination, so the brackets are quoted and you can iterate over the elements.
sample: path=C:\temp;C:\windows;C:\Program Files (x86)
The for-loop will search in
"C:\temp" "C:\windows" "C:\Program Files (x86)"
As code it looks like
setlocal EnableDelayedExpansion
set "searchPath=!path:;=" "!"
for %%c in ("!searchPath!") do (
if exist "%%~c\xyz.exe" set xyz=OK
)

You can use the short names of the folder for this purpose. This is how you do it.
Open command promt in Windows.
Go to C drive (or the drive in which you have the Program Folder)
Type the following and
c:\> dir /x <Hit Enter>
This will return the short forms of all folders.
You will notice now that "\Program Files (x86)" will be represented as "PROGRA~2" (or an equivalent short name).
This is what I use to prevent any errors while creating Batch scripts.
For more options see here.
http://www.computerhope.com/dirhlp.htm
Exlpanation for "dir /x"
"This displays the short names generated for non-8dot3 file names. The format is that of /N with the short name inserted before the long name. If no short name is present, blanks are displayed in its place."

Related

Bash robocopy from text file containing path to folders and files to copy with special characters

I had a bash xcopy script, but got a lot of issues. After a lot of searching and reading I guess robocopy was a better tool to do the copy.
(The script must run on windows 10 computers without installing anything else and without internet access)
I'm trying to make a bash script that copy (with robocopy) some local network folders and files to a local custom directory. The aim is to be able to access to the files off from the local network.
The path to folders and files are stored inside a txt file (each line = a path)
I want to keep the structure of folder I save locally.
For example the folder X:\Path\to some\local\network\folder\with\some & characters\ will result in C:\PathTolocalFolder\Path\to some\local\network\folder\with\some & characters\ (without the X:\ letter)
Based on many similar questions (but not all at the same time) I have done this :
#echo off
SETLOCAL EnableDelayedExpansion
cls
cd C:
chcp 28591 > nul
for /f "delims=*" %%a in ('type "X:\path with spaces & specials characters\List.txt"') do (
REM echo %%a
REM echo !%%a!
echo %%a to C:\PathTolocalFolder!%%a!
ROBOCOPY "%%~a" "C:\PathTolocalFolder!%%a!" /S /A+:RA /R:1 /W:5
)
It is partially a success, but :
As there are special characters everywhere in paths and files names, I got some issues. Specially with & characters. My double quotes doesn't solve the problem. How could I go better?
For some cases, I want to save some files but not the whole directory where they are. The full path to the file is inside the text file. But as robocopy needs to add a space between folder path and file filter I have do some manipulation. How can I detect and extract the file name when there is one to adapt the robocopy command?
I want to use an exclusion list like I was doing before with xcopy. But robocopy doesn't accept a file in input for exclusions. I tried this to extract the exclusion file:
for /f "usebackq tokens*" %%D in ("C:\path to exclusion file\exclusions.txt") do (
if NOT "!dirs!"=="" (
Set dirs=!dirs! "%%D"
else (
Set dirs ="%%D"
)
)
But doesn't really know what I am doing and how to combine with the first part.
Bonus questions I'm using the robocopy log file functionality (removed from below) is there a way to archive (by adding the date in the name for example) previous log file before creating the new one? Is it possible to remove the progress percents in the log file but to display it in the terminal instead? How to use the "/np" option for log file but not for terminal display?
It's hard to me to understand how the delayed variables are working in batch files and how the different methods to read a file or variable are working.
Any help is welcome :)
Sorry for my bad English skills
thank for having read

Run Batch Script Across Subfolders (Recursively)

I regularly have to rename hundreds of files across a subfolder structure. I have been creating a batch file consisting of all my rename commands, and manually pasting this into each subfolder to execute one subfolder at a time. I'd like to revise the batch script so that it executes against all subfolders in one fell swoop, run from the parent directory just once.
My renaming is very manual, and so I need to create a discrete entry for each file. For example, here are three lines:
REN STWP01_00669087* BCBSRI-01849351*
REN BCBSRI-01849357* 2011-12-19_BCBSRI-01849357*
REN STWP01_00669094* BCBSRI-01849369*
I've experimented with the FOR /R command, including trying a separate batch file that calls my renaming batch file (via the CALL command). No luck.
I have to assume that this is simple, but I'm a batch novice, so any help would be appreciated.
Thanks!
#Magoo,
Thanks so much for your response. Your approach is going to be far more efficient than my own so far.
A couple of questions. Please bear with me as I am a total novice with batch commands.
Here's what I did: I saved your code to a .BAT file ("RRename.bat"), modified my filenames as per your instructions and saved those to a text file ("Filenames.txt"), and then run this command from the command line: {RRename.bat Filenames.txt}.
The resulting command windows confirm correct renaming. And so I removed the ECHO and PAUSE commands and re-ran. No luck. Just a bunch of Command windows confirming the directory.
Ideally I'd love to save this as a .BAT file and simply drop this in the top-level directory, together with the data file that contains the old names and new names of the files. And so, a double-click of "RRename.bat" will parse the content of "Filenames.txt" and work its way through all subfolders, renaming wherever matches are encountered. Boom.
To that end:
1. How do I make it so {SET "sourcedir=} indicates the current directory (i.e. the directory in which the batch file is located)? This way I wouldn't ever need to change this variable. (I should note that I am running this script on a network location, which requires me to map the drive, resulting in a different drive letter every time.)
2. How do I hard-code the name of the data file into the script itself? My goal is an easily replicated process minimizing user input (save for the content of the data file).
3. How do I stop the individual command windows from appearing? I'll be renaming thousands of files at a time and don't want to see thousands fo corresponding command windows.
Thank you!
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
:: read parameters
SET "filename1=%~1"
SET "filename2=%~2"
IF DEFINED filename2 GOTO name
IF NOT DEFINED filename1 GOTO :EOF
:: 1 parameter - must be filename
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO START /min "ren %%a" "%~f0" %%a
GOTO :eof
:: we have 2 parameters so rename pattern 1 to pattern 2
:name
FOR /r "%sourcedir%" %%a IN ("%filename1%*") DO CALL :process "%%a"
PAUSE
GOTO :EOF
:: Process the filenames and actually do the rename
:process
:: Name of file to be changed - name and extension of %1
SET "changeme=%~nx1"
:: REPLACE up-to-from-pattern with nothing = remainder of name/extension
CALL SET "endpart=%%changeme:*%filename1%=%%"
:: and RENAME...
ECHO(REN "%~1" "%filename2%%endpart%"
GOTO :eof
You would need to change the setting of sourcedir to suit your circumstances.
Revised data file
STWP01_00669087 BCBSRI-01849351
BCBSRI-01849357 2011-12-19_BCBSRI-01849357
STWP01_00669094 BCBSRI-01849369
Aimed at processing the above file, renaming files starting (column1 entries) to start (column2 entries.)
Method:
Run the batch as
batchname filename
This will execute the batch, processing filename
How:
having set the directory name to start processing from, set filename1&2 to the values of the parameters supplied.
If only 1 is supplied, it is the filename, so process it line-by-line and START a new process /min minimised "with the window name in the first set of quotes" and execute this same batch with the data from each line of the file in turn, then finish by going to :eof (end-of-file - built-in to CMD)
The sub-processes all have 2 parameters (eg BCBSRI-01849357 2011-12-19_BCBSRI-01849357) so processing passes to :name. This runs a for /r loop, from the specified source directory, with the name specified from the first column+* and executes :process passing the filenames found as parameter 1.
:process sets changeme to the filename in question, calculates endpart by removing the string filename1 from changeme which will deliver the er, end part.
Then simply rename the supplied filename to the replacement name+that endpart calculated.
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 PAUSE is just to allow the proposed changes to be seen. Once the process has been verified, change the PAUSE to EXIT.
AAMOI, running
*batchname* STWP01_00669094 BCBSRI-01849369
for instance, would execute the recursive-rename from STWP01_00669094* to BCBSRI-01849369*
Sadly, "No luck" is meaningless.
I have made a minor, but significant change to the instructions. The PAUSE should be changed to an EXIT after testing.
After testing, the ECHO(... line should become
REN "%~1" "%filename2%%endpart%"
which actually executes the rename. If you've just deleted the line, it would explain the no-visible-result.
Having restored the original code and verified against a small representative dummy subtree, change the echo(... line and test again. The filenames should change. If not, something is dreadfully wrong. Needless to say, this works perfectly happily for me...
Then try again with the PAUSE changed to EXIT. This time, the windows generated will appear on the taskbar and then disappear when the rename for that line of the input file has finished. This will happen once for BCBSRI-01849357 rentwo for instance - not once for each individual file rename occurring.
To hard-code the filename, remove the line
IF NOT DEFINED filename1 GOTO :EOF
and replace
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO START /min "ren %%a" "%~f0" %%a
with
FOR /f "usebackqdelims=" %%a IN ("YOURFILENAMEHERE") DO START /min "ren %%a" "%~f0" %%a
For the "run from here" command, change
SET "sourcedir=U:\sourcedir"
to
SET "sourcedir=."
. means "the current directory"
If you place thisbatchfilename.bat into any directory on your PATH then you can run the routine simply by executing thisbatchfilename.
You can display your path by typing
path
at the prompt. PATH is the sequence of directories searched by windows to find an executable if it isn't found in the current directory. To chane path, google "change path windows" - experienced batchers create a separate directory on the path for batch files. Sometimes, they name the directory "Belfry".

Using dos, how can I rename existing folders switching the date parts around?

I have a set of folders already named mm-dd-yyyy (for example 01-01-2014) but they will be more useful named yyyy-mm-dd (for example 2014-01-01). Using dos, how can I rename the folders switching the date parts around?
Assuming that you're talking about cmd.exe rather than the ancient MS-DOS command.com, you can do this reasonably easily(1).
The idea is to iterate over all directories in the current directory, using for /d. Then, for each one that matches a specific pattern (99-99-9999), you can use string manipulation to construct a rename command.
The checking for a correct format can be done with the regular expression capability of findstr.
#echo off
#setlocal enableextensions enabledelayedexpansion
rem Process every file. For each file with a valid format,
rem construct a rename command.
for /d %%a in (*) do (
set full=%%a
call :isvalidfmt !full!
if !res!==true (
set d2=!full:~0,2!
set m2=!full:~3,2!
set y4=!full:~6!
echo ren !full! !y4!-!m2!-!d2!
)
)
endlocal
goto :eof
rem Use findstr regex option to see if file name is correct format.
:isvalidfmt
set res=true
echo %1|findstr /r "^[0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]$" >nul:
if errorlevel 1 set res=false
goto :eof
Note that the script above (let's call it rengen.cmd) simply outputs the rename commands, it does not actually rename the files. That's good practice so you can see what it's going to do before you destroy your directories :-)
To actually rename the files (once you've confirmed it's safe), simply capture the output to another file then run that:
rengen >nextren.cmd
nextren
(1) If you are talking about command.com, I can't help you out there. The command interpreter has come a long way since those bad old days and the one that came with MS-DOS is seriously under-powered.
use dir and export to a file. Take it to Excel and create two columns, one with current name and one with new name and then bring it back to notepad and add RENAME command to each row as a prefix.
RENAME cuurentfilename newfilename is the command syntax.

Batch parameter %~s1 gives incorrect 8.3 short name

I'm trying to write a batch file in Windows XP that takes in a fully-qualified path name and outputs the 8.3 short name version...
#echo off
echo "%~s1"
I have come across one particular case where this outputs an incorrect path and file...
C:\>test.bat "C:\Documents and Settings\angus\Local Settings\Temporary Internet Files\Content.IE5\2JSTM34V\62[1].ja2"
"C:\DOCUME~1\angus\LOCALS~1\TEMPOR~1\Content.IE5\2JSTM34V\62_1_~1.JA2M34V\62[1].ja2"
Note that the above output ("C:\DOCUME~1\angus\LOCALS~1\TEMPOR~1\Content.IE5\2JSTM34V\62_1_~1.JA2M34V\62[1].ja2") does not exist. If I remove the ".JA2M34V\62[1]" section from that output, however, then the resulting string would be a valid path to the original input file.
This seems to be a problem with the use of brackets ([]) in the filename. If I create a file 62.ja2 in the same directory, the output will be correct...
C:\>test.bat "C:\Documents and Settings\angus\Local Settings\Temporary Internet Files\Content.IE5\2JSTM34V\62.ja2"
"C:\DOCUME~1\angus\LOCALS~1\TEMPOR~1\Content.IE5\2JSTM34V\62.ja2"
Is this a bug in Windows? Does anybody know if there's a workaround to allow the batch file to properly handle this filename?
It's not a bug in your code, it's a bug of XP!
With Vista the same code works.
It looks like a sort of a buffer corruption.
It depends of the length of the last directory name, the last characters are copied to the "short name".
And it only occurs if in the filename is one or more characters out of [];,+=<space>
A short test case
#echo off
setlocal EnableDelayedExpansion
set myDir=
set myFile=a[1].bat
set map=123456789ABCDEFGHIJKLMNOPQRSTUVW
for /L %%n in (0 1 26) do (
set "myDir=!myDir!!map:~%%n,1!"
md !myDir!
echo dummy > "!myDir!\!myFile!"
echo Dir=!myDir!
for %%X in ("!myDir!\!myFile!") do echo %%~sX
echo(
del "!myDir!\!myFile!" > nul
rd !myDir!
)
The results of the last lines
Dir=123456789A
C:\Projekte\batch\123456~1\A_1_~1.BAT
Dir=123456789AB
C:\Projekte\batch\123456~1\A_1_~1.BATt
Dir=123456789ABC
C:\Projekte\batch\123456~1\A_1_~1.BATat
Dir=123456789ABCD
C:\Projekte\batch\123456~1\A_1_~1.BATbat
Dir=123456789ABCDE
C:\Projekte\batch\123456~1\A_1_~1.BAT.bat
Dir=123456789ABCDEF
C:\Projekte\batch\123456~1\A_1_~1.BAT].bat
Dir=123456789ABCDEFG
C:\Projekte\batch\123456~1\A_1_~1.BAT1].bat
Dir=123456789ABCDEFGH
C:\Projekte\batch\123456~1\A_1_~1.BAT[1].bat
Dir=123456789ABCDEFGHI
C:\Projekte\batch\123456~1\A_1_~1.BATa[1].bat
Dir=123456789ABCDEFGHIJ
C:\Projekte\batch\123456~1\A_1_~1.BAT\a[1].bat
Dir=123456789ABCDEFGHIJK
C:\Projekte\batch\123456~1\A_1_~1.BATK\a[1].bat
Dir=123456789ABCDEFGHIJKL
C:\Projekte\batch\123456~1\A_1_~1.BATKL\a[1].bat
Dir=123456789ABCDEFGHIJKLM
C:\Projekte\batch\123456~1\A_1_~1.BATKLM\a[1].bat
Dir=123456789ABCDEFGHIJKLMN
C:\Projekte\batch\123456~1\A_1_~1.BATKLMN\a[1].bat
Dir=123456789ABCDEFGHIJKLMNO
C:\Projekte\batch\123456~1\A_1_~1.BATKLMNO\a[1].bat
Dir=123456789ABCDEFGHIJKLMNOP
C:\Projekte\batch\123456~1\A_1_~1.BATKLMNOP\a[1].bat
Dir=123456789ABCDEFGHIJKLMNOPQ
C:\Projekte\batch\123456~1\A_1_~1.BATKLMNOPQ\a[1].bat
Dir=123456789ABCDEFGHIJKLMNOPQR
C:\Projekte\batch\123456~1\A_1_~1.BATKLMNOPQR\a[1].bat

Looking for a simple Batch script that modifies file name

I have a list of files in a folder that end with .swf.
I want to change all those files from X.swf to X<some number>.swf.
How can I do that?
This little script will change all *.swf files into the equivalent *_42.swf files.
#setlocal enableextensions enabledelayedexpansion
#echo off
for /f %%a in ('dir /b *.swf') do (
set fspec=%%a
set newfspec=!fspec:~0,-4!_42.swf
echo ren !fspec! !newfspec!
)
endlocal
Actually, as it stands now, it will just echo the commands that it wants to execute. Once you're happy they're correct, you can just remove the echo from that renaming line above.
It works by using for /f to get a list of all SWF files and then using string manipulation to:
remove the last four characters (the.swf extension); then
add a new _42.swf extension onto the end.
And, please, make sure you back them up first :-)
You could use the following one-liner directly from the command prompt:
FOR %F IN (*.swf) DO RENAME "%F" "%~nF123.*"
where 123 stands for your number of choice.
Alternatively you could create a batch file and take advantage of its ability to accept parameters. Use the following script:
#ECHO OFF
SET "suffix=%~1"
FOR %%F IN (*.swf) DO RENAME "%%F" "%%~nF%suffix%.*"
Now if the batch's name is renamer.bat, you can invoke it like this:
renamer.bat 2011
and it will add 2011 to the name of every .swf file in the current directory.
Assuming <X> in your description is supposed to be constant and you don't explicitly require a batch script to solve your problem, you can use Windows Explorer as mentioned in an article by Microsoft titled "Rename a file".
Here's a an extract from said article:
"You can also rename several files at one time, which is useful for grouping related items. To do this, select the files [then press F2]. Type one name, and then each of the files will be saved with the new name and a different sequential number at the end (for example, Renamed File (2), Renamed File (3), and so on)."

Resources