So here's my issue:
I want to use %cd% so a user can execute a script anywhere they want to place it, but if %cd% contains spaces, then it will fail (regardless of quotes). If I hardcode the path, it will function with quotes, but if it is a variable, it will fail.
Fails: (if %cd% contains spaces)
"%cd%\Testing.bat"
Works:
"C:\Program Files\Testing.bat"
Any ideas?
%CD% is not the right way to do it, as it indicates the directory where the user was located when invoking the script, not the directory where the script resides.
Use %~dp0 instead to extract the drive and path information from %0:
REM C:\Program Files\test_caller.bat
#echo I am the caller and I reside in: "%~dp0"
#"%~dp0\test.bat"
...
REM C:\Program Files\test.bat
#echo Yippeee!
...
C:\>"\Program Files\test_caller.bat"
I am the caller and I reside in: "C:\Program Files\"
Yippeee!
C:\>e:
E:\>"C:\Program Files\test_caller.bat"
I am the caller and I reside in: "C:\Program Files\"
Yippeee!
Related
I am trying to iterate files in a folder and process them with another batch file inside the do loop. It works with echo but as soon as I use the variable as input to the program, it echoes the () part and everything inside.
Here's what I'm trying to do.
#echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
for /r %%f in (/folder/*) do (
set name="%%~nf"
echo !name! <--- ok
process.bat !name! <--- echoes () and commands inside this do loop
)
ENDLOCAL
The process.bat just capitalizes the first letter of the filename and echoes it for debug or confirmation.
A batch file must be called from within a batch file using command call as otherwise Windows command processor continues processing on other batch file with never returning back to initial batch file.
See also: How to call a batch file that is one level up from the current directory?
Please read excellent answer on batch file echo on/off not working properly written by dbenham for the reason on getting suddenly the commands executed by FOR output after first execution of process.bat without using command CALL. I cannot explain better what happens in this case.
The directory separator on Windows is the backslash character \ and not the forward slash / as on Linux or Mac. Windows supports also / in file/folder paths for compatibility reasons by automatically replacing all / by \ before accessing the Windows file systems, but a good written script uses 100% correct syntax and does not depend on automatic corrections done by other programs. / is used on Windows mainly for command line switches.
The usage of / instead of \ can result in an unexpected behavior. For example run a batch file with following content:
#echo off
echo Files in directory %SystemRoot:\=/%/:
for %%I in (%SystemRoot:\=/%/*) echo %%I
echo/
pause
echo/
echo Files in directory %SystemRoot%\:
for %%I in (%SystemRoot%\*) echo %%I
echo/
pause
The first FOR using C:/Windows/* as wildcard pattern outputs the file names with just drive letter + colon + file name + file extension. The file path \Windows\ is missing in output file names. The second FOR loop using C:\Windows\* as wildcard pattern outputs the full qualified file names, i.e. drive letter + colon + file path + file name + file extension.
A file/folder path starting with \ references a directory or file relative to root directory of current DRIVE.
This is explained by the Microsoft documentation Naming Files, Paths, and Namespaces.
It looks like folder is a subdirectory in directory of the executed batch file. In this case / or \ at beginning of folder path is definitely not correct. The backslash at beginning can be omitted or .\ is used to reference the directory folder in current directory on execution of the batch file. But the current directory on batch file execution can be also different to directory containing the executed batch file, for example on running the batch file as administrator, or on running the batch file as scheduled task, or on running the batch file from a network resource accessed using a UNC path. For that reason it is advisable to reference explicitly subdirectory folder in directory of the batch file.
Delayed environment variable expansion is not needed as long as the file name assigned currently to the loop variable does not need to be modified other than the modifiers of for support it. A command line like set name="%%~nf" does not work correct with enabled delayed expansion and file name contains one or more ! because of cmd.exe interprets the exclamation mark(s) in file name as beginning/end of a delayed expanded environment variable reference.
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
It looks like a recursive search for non-hidden files is not really needed as otherwise passing just file name without path and file extension would be not enough to get the right file processed by other batch file process.bat.
So the entire task can be done most likely also with:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%I in ("%~dp0folder\*") do call "%~dp0process.bat" "%%~nI"
endlocal
But if the other batch file process.bat expects that the passed file name without file extension and path is in current directory on execution of process.bat, it is necessary to make the subdirectory folder in directory of this batch file first the current directory.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0folder"
for %%I in (*) do call "%~dp0process.bat" "%%~nI"
popd
endlocal
Note: The batch file folder path referenced with %~dp0 always ends with a backslash. Therefore no additional backslash should be used on concatenating this path string with a file/folder name to avoid having finally on execution of the batch file \\ in full qualified file/folder name, although Windows kernel corrects such paths also automatically by removing second backslash in this case.
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.
call /?
echo /?
endlocal /?
popd /?
pushd /?
set /?
setlocal /?
So basically I have a .bat that is inside my System32 folder.
This batch file accepts a parameter input, this input is a file.
I wanted it to be that I could open my Command Prompt, and for example do
batchfile text.txt
And it would pass test.txt into batchfile.bat. Obviously for my terminal to do this it needs to be in System32.
That is where my issue is. Because the batch file is in System32, when executing the command, it changes my directory to System32.
However the parameter I give it is a file. And when the command is executed and it changes the directory to System32, obviously it can no longer access the file.
How can I get around this?
Before you change directories, expand the filename to its fully-qualified filename and then reference it that way:
#echo off
for %%F in (%1) do set USR_REQFNM=%%~dpnxF
C:
cd \Windows\System32
echo The requested file is "%USR_REQFNM%"
goto ENDIT
REM Cleanup
:ENDIT
set USR_REQFNM=
I want to create a shortcut,bat or exe that will open the command line in a specific folder within the current path the shortcut/bat/exe resides.
My example being the shortcut/bat/exe is located in
C:\Users\"user"\Desktop
I want to open the cmd in Folder
C:\Users\"user"\Desktop\Folder
But I don't want it to be dependent on the full path. I want to be able to move the exe and folder together to another location and it still work. So I want the exe to start cmd.exe in current path + \Folder
%windir%\system32\cmd.exe + \Folder
you could just put "cd folder" in the bat file.
exe would depend on what you use to create it, and don't know about shortcuts.
Also you can use %cd% in bat files to get current path.
C:\Users\user>echo %windir%\system32\cmd.exe %cd%\Folder
C:\Windows\system32\cmd.exe C:\Users\user\Folder
See call /? for a list of filenames/paths. This is in a batch not shortcut. %0 is the batchfile.
cd "%~dp0\folder"
Substitution of batch parameters (%n) has been enhanced. You can
now use the following optional syntax:
%~1 - expands %1 removing any surrounding quotes (")
%~f1 - expands %1 to a fully qualified path name
%~d1 - expands %1 to a drive letter only
%~p1 - expands %1 to a path only
%~n1 - expands %1 to a file name only
%~x1 - expands %1 to a file extension only
%~s1 - expanded path contains short names only
%~a1 - expands %1 to file attributes
%~t1 - expands %1 to date/time of file
%~z1 - expands %1 to size of file
%~$PATH:1 - searches the directories listed in the PATH
environment variable and expands %1 to the fully
qualified name of the first one found. If the
environment variable name is not defined or the
file is not found by the search, then this
modifier expands to the empty string
The modifiers can be combined to get compound results:
%~dp1 - expands %1 to a drive letter and path only
%~nx1 - expands %1 to a file name and extension only
%~dp$PATH:1 - searches the directories listed in the PATH
environment variable for %1 and expands to the
drive letter and path of the first one found.
%~ftza1 - expands %1 to a DIR like output line
I have a batch file which is in a directory and must be run from there as well because it updates files within this directory.
This works perfectly fine, except when the user runs the batch file as administrator (required on Vista). Then the starting directory is C:\Windows\System32.
Is there any way to still be able to know from which directory the batch file was run?
I dont want the user to enter the directory manually.
Try to access the batch files path like this:
echo %~dp0
For more information see the following quote from the command for /? that describes how the above command works:
You can now use the following optional syntax:
%~I - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
environment variable and expands %I to the
fully qualified name of the first one found.
If the environment variable name is not
defined or the file is not found by the
search, then this modifier expands to the
empty string
The modifiers can be combined to get compound results:
%~dpI - expands %I to a drive letter and path only
%~nxI - expands %I to a file name and extension only
%~fsI - expands %I to a full path name with short names only
%~dp$PATH:I - searches the directories listed in the PATH
environment variable for %I and expands to the
drive letter and path of the first one found.
%~ftzaI - expands %I to a DIR like output line
Better than cd is pushd which will
change drive letter if starting from D:\...
assign a drive letter if on a UNC network path
So pushd %~dp0 is good.
Good practice is then to call popd when done.
This should solve your problem by setting the working directory for the batch file back to the current directory:
Include these two lines at the top of your .bat script:
#setlocal enableextensions
#cd /d "%~dp0"
Found at: http://www.codeproject.com/Tips/119828/Running-a-bat-file-as-administrator-Correcting-cur
To fix this problem, include these two lines at the top of your .bat script:
#setlocal enableextensions
#cd /d "%~dp0"
I use:
cd %0..
at the beginning of the batch file to change directory to the directory where the batch file was started in.
-Mathew
#setlocal enableextensions
#cd /d "%~dp0"
You can CD directly from the file name by adding the parent (not tested in windows 8.x, but has worked "forever" as far as I can remember).
CD %FILENAME%\..
and CD will change drives as well using /D, which is shown above but not explicitly mentioned so might be missed.
CD /D %FILENAME%\..
(FOR /?
IF /?
SET /?
CALL /?
GOTO /?
all provide highly useful reading if you use cmd.exe, I reread them once in a while.)
A working solution here:
http://www.vistax64.com/vista-general/79849-run-administrator-changes-default-directory.html
FOR /F %%I IN ("%0") DO SET BATDIR=%%~dpI
ECHO The batch file is located in directory %BATDIR%
I'm looking at a batch file which defines the following variables:
set _SCRIPT_DRIVE=%~d0
set _SCRIPT_PATH=%~p0
What do %~d0 or %~p0 actually mean?
Is there a set of well-known values for things like current directory, drive, parameters to a script?
Are there any other similar shortcuts I could use?
The magic variables %n contains the arguments used to invoke the file: %0 is the path to the bat-file itself, %1 is the first argument after, %2 is the second and so on.
Since the arguments are often file paths, there is some additional syntax to extract parts of the path. ~d is drive, ~p is the path (without drive), ~n is the file name. They can be combined so ~dp is drive+path.
%~dp0 is therefore pretty useful in a bat: it is the folder in which the executing bat file resides.
You can also get other kinds of meta info about the file: ~t is the timestamp, ~z is the size.
Look here for a reference for all command line commands. The tilde-magic codes are described under for.
They are enhanced variable substitutions. They modify the %N variables used in batch files. Quite useful if you're into batch programming in Windows.
%~I - expands %I removing any surrounding quotes ("")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
environment variable and expands %I to the
fully qualified name of the first one found.
If the environment variable name is not
defined or the file is not found by the
search, then this modifier expands to the
empty string
You can find the above by running FOR /?.
Yes, There are other shortcuts that you can use which are given below.
In your command, ~d0 would mean the drive letter of the 0th argument.
~ expands the given variable
d gets the drive letter only
0 is the argument you are referencing
As the 0th argument is the script path, it gets the drive letter of the path for you. You can use the following shortcuts too.
%~1 - expands %1 removing any surrounding quotes (")
%~f1 - expands %1 to a fully qualified path name
%~d1 - expands %1 to a drive letter only
%~p1 - expands %1 to a path only
%~n1 - expands %1 to a file name only
%~x1 - expands %1 to a file extension only
%~s1 - expanded path contains short names only
%~a1 - expands %1 to file attributes
%~t1 - expands %1 to date/time of file
%~z1 - expands %1 to size of file
%~$PATH:1 - searches the directories listed in the PATH
environment variable and expands %1 to the fully
qualified name of the first one found. If the
environment variable name is not defined or the
file is not found by the search, then this
modifier expands to the empty string
%~dp1 - expands %1 to a drive letter and path only
%~nx1 - expands %1 to a file name and extension only
%~dp$PATH:1 - searches the directories listed in the PATH
environment variable for %1 and expands to the
drive letter and path of the first one found.
%~ftza1 - expands %1 to a DIR like output line
This can be also found directly in command prompt when you run CALL /? or FOR /?
From Filename parsing in batch file and more idioms - Real's How-to:
The path (without drive) where the script is : ~p0
The drive where the script is : ~d0
Another tip that would help a lot is that to set the current directory to a different drive one would have to use %~d0 first, then cd %~dp0. This will change the directory to the batch file's drive, then change to its folder.
For #oneLinerLovers, cd /d %~dp0 will change both the drive and directory :)
Hope this helps someone.
Some gotchas to watch out for:
If you double-click the batch file %0 will be surrounded by quotes. For example, if you save this file as c:\test.bat:
#echo %0
#pause
Double-clicking it will open a new command prompt with output:
"C:\test.bat"
But if you first open a command prompt and call it directly from that command prompt, %0 will refer to whatever you've typed. If you type test.batEnter, the output of %0 will have no quotes because you typed no quotes:
c:\>test.bat
test.bat
If you type testEnter, the output of %0 will have no extension too, because you typed no extension:
c:\>test
test
Same for tEsTEnter:
c:\>tEsT
tEsT
If you type "test"Enter, the output of %0 will have quotes (since you typed them) but no extension:
c:\>"test"
"test"
Lastly, if you type "C:\test.bat", the output would be exactly as though you've double clicked it:
c:\>"C:\test.bat"
"C:\test.bat"
Note that these are not all the possible values %0 can be because you can call the script from other folders:
c:\some_folder>/../teST.bAt
/../teST.bAt
All the examples shown above will also affect %~0, because the output of %~0 is simply the output of %0 minus quotes (if any).
%~d0 gives you the drive letter of argument 0 (the script name), %~p0 the path.
This code explains the use of the ~tilde character, which was the most confusing thing to me. Once I understood this, it makes things much easier to understand:
#ECHO off
SET "PATH=%~dp0;%PATH%"
ECHO %PATH%
ECHO.
CALL :testargs "these are days" "when the brave endure"
GOTO :pauseit
:testargs
SET ARGS=%~1;%~2;%1;%2
ECHO %ARGS%
ECHO.
exit /B 0
:pauseit
pause
It displays the current location of the file or directory that you are currently in. for example; if your batch file was in the desktop directory, then "%~dp0" would display the desktop directory. if you wanted it to display the current directory with the current file name you could type "%~dp0%~n0%~x0".