how to properly pass file with spaces as parameter using call - batch-file

I have written a small script to read all the files in the given directory and check for occurrence of a string.
This seems to work until I call %1 in the called .bat.
The problem I am facing is that when I use the call function the new .bat file that is executed doesn't have the full name of the parameter given.
The script
NET USE O: "\\MyNetworkDrive\MySelectedFolder"
IF NOT "%~1"=="" GOTO ADDV
SET VAR=
FOR /F "tokens=* USEBACKQ" %%F IN (`DIR *.* /s/b/A:-d-h`) DO FIND /i "stringToFind" "%%F" && CALL %0 %%F
SET VAR
GOTO END
:ADDV
SET VAR=%VAR%!%1
:END
ECHO %VAR% > search.txt
pause
As you can see the script checks if %1 not equals empty string.
Now in the for do loop I check for a string in the file and if the file has one it calls the same script with the file path as parameter (the correct file path e.g. O:\MyNetworkDrive\MySelectedFolder\My File.xls)
however when I call the %1 in the called .bat it equals O:\MyNetworkDrive\MySelectedFolder\My.
What is causing the %1 variable to not contain the correct file path?
How can I solve this?
All that I could find on the internet about this is about quoting the path with double quotes and using %~1 to negate the quotes in the variable, which I have used correctly as far as I know.

Related

Find the path of executable and store the executable in a variable

I am trying to create a batch file:
The batch file will locate the path of executable first. Then, the path will be stored in a variable for later use.
This is my code:
#echo off
setlocal
set directoryName=dir/s c:\ABCD.exe
rem run command
cmd /c %directoryName%
pause
endlocal
The command prompt does return me with the executable's path but the path is not stored in the variable. Why is it so?
Reading your question, it appears that you're not really wanting to save the path of the executable file at all, but the file name complete with it's full path:
I prefer the Where command for this type of search, this example searches the drive in which the current directory resides:
#Echo Off
Set "mPth="
For /F "Delims=" %%A In ('Where /R \ "ABCD.exe" /F 2^>Nul'
) Do Set "mPth=%%A"
If Not Defined mPth Exit /B
Rem Rest of code goes here
The variable %mPth% should contain what you need. I have designed it to automatically enclose the variable value in doublequotes, if you wish to not have those, change %%A on line 4 to %%~A. If the file is not found then the script will just Exit, if you wish it to do something else then you can add that functionality on line 5.
Note: the code could find more than one match, if it does it will save the variable value to the last one matched, which may not be the one you intended. A robust solution might want to include for this possibility.
Edit (this sets the variable, %mPth% to the path of the executable file only)
#Echo Off
Set "mPth="
For /F "Delims=" %%A In ('Where /R \ "ABCD.exe" /F 2^>Nul'
) Do Set "mPth=%%~dpA"
If Not Defined mPth Exit /B
Set "mPth=%mPth:~,-1%"
Rem Rest of code goes here
Lets walk through your code
set directoryName=dir/s c:\ABCD.exe
This fills the variable directory name with the value dir/s c:\ABCD.exe.
cmd /c %directoryName%
This executes the command in directoryname. There is no line in your code that saves the files location to a variable.
Extracting the path of a file can be done as follows
#echo off
setlocal
set executable=c:\location\ABCD.exe
FOR %%A IN ("%executable%") DO Set executablepath=%%~dpA
echo executablepath: %executablepath%
pause
endlocal
%executablepath% will contain c:\location\
The value that you are assigning to directoryname is dir /s c:\abc.exe.
this value is then substituted for %directoryname% in your cmd line, which executes the command dir/s..., showing you the location(s) of abc.exe in the familiar dir format.
If what you want is just the directoryname in directoryname, then you need
for /f "delims=" %%a in ('dir /s /B /a-d "c:\abc.exe"') do set "directoryname=%%~dpa"
which will first execute the dir command, then process each line of output from that command and assign it in its entirety to %%a.
The dir command shown would "display" the matching names found in the nominated directory (c:\) and its subdirectories (/s) in basic form (/b) - that is, names only, no size or date or report-headers or report-footers, and a-d without directorynames (should they match the "mask" abc.exe)
The delims= option to the for /f command instructs that the entire line as output by the command in single-quotes, be assigned to %%a.
When the result is assigned to the variable directoryname, only the Drive and Path parts are selected by using the ~dp prefix the the a.
Note that only the very last name found will be assigned to the variable as any earlier assignment will be overwritten by a succeeding assignment.
This may or may not be what you are looking for. This script searches through the PATH variable and looks for files that have and extension in the PATHEXT variable list.
#SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
#SET EXITCODE=1
:: Needs an argument.
#IF "x%1"=="x" (
#ECHO Usage: %0 ^<progName^>
GOTO TheEnd
)
#set newline=^
#REM Previous two (2) blank lines are required. Do not change!
#REM Ensure that the current working directory is first
#REM because that is where DOS looks first.
#PATH=.;!PATH!
#FOR /F "tokens=*" %%i in ("%PATH:;=!newline!%") DO #(
#IF EXIST %%i\%1 (
#ECHO %%i\%1
#SET EXITCODE=0
)
#FOR /F "tokens=*" %%x in ("%PATHEXT:;=!newline!%") DO #(
#IF EXIST %%i\%1%%x (
#ECHO %%i\%1%%x
#SET EXITCODE=0
)
)
)
:TheEnd
#EXIT /B %EXITCODE%
Note that this may find multiple executables. It may also find multiple types of executables. The current directory is also included first since that is what the shell, cmd.exe, does.
M:>whence wc
.\wc.BAT
.\wc.VBS
C:\Users\lit\bin\wc.BAT
C:\Users\lit\bin\wc.VBS

Trying to write a calling batch file but keep getting "cannot find" error

I am trying to write a batch file that calls another which replaces two files in a directory. Here is my code:
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
call C:\%mmcIpath%\spc_we_replace_CED+CEDU.bat
Whenever I set the temporary environment variable, it says the directory cannot be found.
--ADDITIONAL INFO--
I run a Minecraft launcher called MultiMC5; it has a feature which runs commands - but only one command, for some reason. So I wanted it to call a batch file to run multiple commands.
My main batch file is in "C:...\MultiMC\instances", but I want the program to be able to call it. It cannot, as it works within a subdirectory called "CED (210 mods-)". So I placed another batch in the subdirectory to call the main one (I wanted to do the same for a second subdirectory called "CEDU (300+ mods-)"). I got this error: "The system cannot find the path specified.". It happened when I set the path.
I'm using Windows 8.1 and have searched for tips on how to use wildcards and on how to use FOR loops, but none of the wildcard methods have worked for me and I cannot understand FOR loops at all. I have also tried to remove and add things like quotation marks in an attempt to fix it, but that didn't work either.
My question:
Is the set command compatible with wildcards and if so, how do I get this to work?
It looks like your problem is that the main batch file can be on any drive and you want to call other batch files with a path relative to the location of main batch file. Is that correct?
You can get the drive with %~d0, path with %~p0 and drive + path with %~dp0. See the example below and execute this little batch file stored in several different directories:
#echo off
echo Batch is stored on drive %~d0
echo in the directory %~p0
echo resulting in path %~dp0
So you can use argument 0 referenced by %0 containing always name of batch file with full path using the syntax above explained in help of command FOR displayed with entering for /?in a command prompt window to call the other batch files with a path depending on path of the main batch file.
Now what we have here is a classic XY problem - being asked about a solution, not the underlying issue.
Here's a possible resolution:
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
I've left the original setting of mmcIpath in place, and replaced it with a form to suit my system.
The approach is to execute a dir/s/b/ad command (directory, basic format, with subdirectories, directory names only) and filter it using findstr. I chose switches /i (case-insensitive) /e (must end with string) /r regular-expression /c: (following is one string to be matched).
The regex is constructed according to findstr's rules - \ needs to be doubled if it is to be used as a literal; .* means 'any number of any character'
This should provide a list of literal directory names which get through the filter. Look in the directory found for the filename, call the target file if found. The required CALL commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO CALL to CALL to actually execute the files.
The following ECHO GOTO is there to show that the loop can be broken after finding the first target file, if desired. You havent't indicated whether you want to run only the first or run all of the targets found.
Here's my test source. I use U: for testing data. Your system would likely be different.
#ECHO OFF
SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
set "mmcIpath=\mmc-stable-win32\MultiMC\instances"
FOR /l %%a IN (1,1,4) DO MD u:\%%a%mmcIpath% 2>nul
FOR /l %%a IN (2,2,4) DO COPY NUL u:\%%a%mmcIpath%\spc_we_replace.bat 2>NUL >nul
ENDLOCAL
ENDLOCAL
#ECHO OFF
SETLOCAL
set mmcIpath="C:"*"\mmc-stable-win32\MultiMC\instances"
set "mmcIpath=U:\\.*\\mmc-stable-win32\\MultiMC\\instances"
SET "targetbat=spc_we_replace.bat"
FOR /f "delims=" %%a IN (
'dir /b/s /ad "%mmcIpath:~0,3%"^|findstr /e /i /r /c:"%mmcIpath%" '
) DO (
IF EXIST "%%a\%targetbat%" (
ECHO CALL "%%a\%targetbat%"
ECHO GOTO nextstep
)
)
:nextstep
GOTO :EOF
Note that the first section is merely establishing u:\1\mmc-stable-win32\MultiMC\instances to u:\4\mmc-stable-win32\MultiMC\instances then creating a dummy file spc_we_replace.bat in u:\2\mmc-stable-win32\MultiMC\instances and u:\4\mmc-stable-win32\MultiMC\instances.
The string assigned to mmcIath in the second section is according to findstr's syntax rules - each \ is doubled, .* means "any number of any character". You would have to modify that string to suit your system. Note that "%mmcIpath:~0,3%" gratuitously takes the first 3 characters from the string. In my case, that would be U:\. YMMV

Batch renaming last few characters of files

I'm trying to create a batch file that would rename a bunch of files in a folder. These files would have a naming of something like: blah(lol).txt. There will always be a four letters, followed by an open bracket, three letters, and finally a close bracket.
I want the batch file to remove the bracketed part of the name of the file, ie. rename the file without the bracketed part.
for %%i IN (*.txt) DO (set name=%%~ni
set name2=%name:~1,4%
ren %%i %name2%)
Why doesn't this work?
Magoo provided an explanation as to why your script failed, as well as a working script.
But in your case, there is no need for a script. A simple REN command is all that is needed:
ren "????(???).txt" "????.*"
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "tokens=1,2,3delims=()" %%a IN (
'dir /b /a-d "%sourcedir%\*(*).*" '
) DO ECHO REN "%sourcedir%\%%a(%%b)%%c" %%a%%b%%c
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.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
simple but works from the folder with the files to be renamed.
#echo off
title Rename Bat
echo This bat must be in the folder that
echo contains the files to be renamed.
:begin
echo Enter File Name
set /p old=
echo Enter New Name
set /p new=
ren "%old%" "%new%"
echo File Renamed
ping -n 3 127.0.0.1 >NUL
goto begin
a much simpler approach ... try a for loop that cycles through all files in your folder
I'm going to use lol as an example of three letter word inside brackets as stated in your question
#echo off
for %%a in (*) do (
rename "%%a" "%%a(lol).exe"
)
to use this batch file you have to place it in the folder containing the files you wanna rename

Passing an argument from one batch file to another

I have 2 batch files.
The first one needs an input argument which is a path of a parent folder. It reads the names of all subfolders inside the parent folder and executes the second batch file for each subfolder.
BATCH FILE 1
#echo off
for /d %%Y in (%1/*) do (
set SubfolderNameAndPath=%%Y
call batch2.bat %SubfolderNameAndPath%
)
The second batch file uses as input argument the SubfolderNameAndPath and executes an Evaluate.exe for all the files that exist in each subfolder. It saves the results of the Evaluate.exe to a text file "results" with an extension that carries the name of the subfolder that each time has been accessed. (results_%~n1.txt).
BATCH FILE 2
#echo off
for %%X in (%1/*) do (
echo Evaluate.exe %%X AnotherArgumentHere -o results_%~n1.txt
)
When I run the batch1 (batch1.bat ParentFolderPath) even if it seems to call the batch2.bat, the batch2.bat is not executed. I believe that something goes wrong with the way that I define the input arguments for the batch2.bat but I cannot figure out what it is.
The %SubfolderNameAndPath% does not contain any spaces. Neither the path to the folder does.
I would really appreciate your help on that.
Well, first, when inside a bracketed pair you can't set a variable then access it with the %'s. You must first (before the for loop) setlocal enabledelayedexpansion, then access your variables with the !'s rather than the %'s.
But since you do not do anything with %SubfolderNameAndPath% anyway, you should just eliminate it.
Second, you need to compensate for paths containing spaces, so hopefully my code below will work out for you. To do this, batch uses a special notation for arguments passed to to remove double quotes around them. So, if %1 = "This string", then %~1 = This string. Also, if %1 = This string, then %~1 still = This string. So there is no drawback to using the %~1 notation, unless you want to retain any double quotes.
So, int batch1.bat, we remove any potential quotes surrounding %1, and then place double-quotes around %~1/*, and also double-quote %%Y just in case there are spaces in it.
batch1.bat
#echo off
for /d %%Y in ("%~1/*") do call batch2.bat "%%~Y"
Then we do the same thing for batch2.bat, but more of it.
batch2.bat
#echo off
for %%X in ("%~1/*") do (
echo Evaluate.exe "%%~X" AnotherArgumentHere -o "results_%~n1.txt"
)
EDIT: 2012/09/05 15:21
How's this grab you? Instead of calling a seprate batch:
for /d %%x in (%1\*) do (
for /f "tokens=*" %%y in ( 'dir /b /a:-d "%%~dpnxx"' ) do (
echo Evaluate.exe %%~nxy AnotherArgumentHere -o "results_%%~nxx.txt"
)
)
(The above can be put all on one line, just remove the brackets.)
I'm assuming the output is:
Evaluate.exe <file_name> AnotherArgumentHere -o "results_<directory_name>.txt"

Absolute Path: Separate the path and save in string

Using batch commands how do I get the folder path/directory from a string?
For example, if I have the string "C:\user\blah\abc.txt" how do I split the string so I can just get the folder part, ie, "C:\user\blah\"?
If pass the string "C:\user\blah\abc.txt" in the command line of a batch file, how do I split that string into just the folder part?
REM // Grab "C:\user\blah\abc.txt" from the command line
SET path="%*"
REM // The following doesn't successfully capture the "C:\user\blah\" part
SET justFolder=%path:~dp1%
the ~dp option only works with the batch parameters (%1 %2 ...) or with FOR substitution parameters (%%a %%b ...). Read HELP CALL.
So, to achieve what you want, try the following code
call :setJustFolder "%*"
echo %justFolder%
goto :eof
:setJustFolder
set justFolder=%~dp1
goto :eof
As an aside note, my personal preference is not to add " around user entered filenames. I would code the previous code simply as
set justFolder=%~dp1
echo %justFolder%
If you want to get the path from a string or from the current working directory is nearly the same.
set "myPath=%~dp1"
echo %myPath%
Or if you want to get it from a variable you could use FOR/F.
set myPath=C:\windows\xyz.txt
for /F "delims=" %%A in ("%myPath%") do echo %%~dpA

Resources