Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch scripting: What's the difference between %0 and %~f0?

I have a Batch script in which I want to get the full path to the script. I'm curious, is there any difference between this:

set scriptpath=%0

and this:

set scriptpath=%~f0

Thanks for helping.

like image 503
James Ko Avatar asked Feb 28 '16 17:02

James Ko


2 Answers

%0 references argument 0 – the name of the batch file – always exactly as specified on command line or in another batch file.

So if a batch file named Test.bat stored in C:\Temp is started for example from within a command prompt window with current directory being C:\ with an execution of temp\test, then %0 is substituted by temp\test on execution of the batch file.

But %~f0 is substituted nearly always by the batch file name with file extension and with complete path – fully qualified file name – and always without double quotes even if the file name or the path contains one or more characters like space or &()[]{}^=;!'+,`~ usually requiring the usage of double quotes.

Therefore the batch file Test.bat stored in C:\Temp with the lines

@echo %0
@echo %~f0

started from within a command prompt window with "temp\test.bat" with current directory being C:\ outputs:

"temp\test.bat"
C:\Temp\Test.bat

There can bee seen here all differences:

  • fully qualified batch file name,
  • always without double quotes and
  • with correct case of all letters.

A description of %~f0 and other modifiers can be read in help of command CALL output on running call /? or in help of command FOR on running for /? in a command prompt window and reading all displayed pages.

Note 1:

The fully qualified batch file name should be assigned to an environment variable if needed later in batch file and the current directory is modified from within the batch file using either CD or PUSHD. For the reason see the answers on What is the reason for batch file path referenced with %~dp0 sometimes changes on changing directory?

Note 2:

Running example batch file above from C:\ just with "temp\test" results in the output:

"temp\test"
C:\Temp\Test

The file extension is missing which is caused by the cmd bug described in the referenced topic of first note. Starting the batch file with temp\test without the double quotes produces the expected output:

temp\test
C:\Temp\Test.bat

The ultimate solution to get the fully qualified file name of the batch file always determined and output correct is:

@echo off
goto Main
:GetFullBatchFileName
set "%1=%~f0" & goto :EOF
:Main
setlocal EnableExtensions DisableDelayedExpansion
echo %0
call :GetFullBatchFileName FullBatchFileName
setlocal EnableDelayedExpansion & echo !FullBatchFileName!& endlocal
endlocal

This code works even for a batch file C:\Temp\Development & !Test!(!)\BestCode.bat being executed from C:\ with "temp\development & !test!(!)\bestcode" producing the output:

"temp\development & !test!(!)\bestcode"
C:\Temp\Development & !Test!(!)\BestCode.bat

Why using delayed expansion to output the full batch file name?

The output of a file/folder name assigned to an environment variable like FullBatchFileName with command ECHO without surrounding " requires the usage of delayed expansion as otherwise an ampersand in file/folder name would be interpreted as unconditional AND operator and not as literal character being part of the file/folder name to output by ECHO.

Example on what could happen on not using delayed expansion on output of a file/folder name assigned to an environment variable without surrounding ":

@echo off
goto Main
:GetFullBatchFileName
set "%1=%~f0" & goto :EOF
:Main
setlocal EnableExtensions DisableDelayedExpansion
echo %0
call :GetFullBatchFileName FullBatchFileName
echo %FullBatchFileName%
endlocal

This batch file code stored in C:\Temp\Development & !Test!(!)\NotGood1.bat results in execution from C:\ with "temp\development & !test!(!)\notgood1" in the output:

"temp\development & !test!(!)\notgood1"
C:\Temp\Development
'!Test!' is not recognized as an internal or external command,
operable program or batch file.

So the Windows command processor cmd interprets & in the value of the environment variable FullBatchFileName as unconditional command operator AND. For that reason ECHO outputs just the part of the fully qualified batch file name up to & and the rest is interpreted by cmd.exe as a second command to execute after execution of command ECHO. cmd.exe makes in this case lots of file system accesses to find an executable or script file which could be meant by !Test!(!)\NotGood1.bat and finally after not finding something suitable outputs the error message.

Why is delayed expansion not enabled from the beginning?

Delayed expansion cannot be enabled from the beginning as this would result in interpreting ! in file/folder name strings as beginning/end of a delayed expanded variable reference as it can be seen with the following code:

@echo off
goto Main
:GetFullBatchFileName
set "%1=%~f0" & goto :EOF
:Main
setlocal EnableExtensions EnableDelayedExpansion
set "Test="
echo %0
call :GetFullBatchFileName FullBatchFileName
echo !FullBatchFileName!
endlocal

This batch file code stored in C:\Temp\Development & !Test!(!)\NotGood2.bat results in execution from C:\ with "temp\development & !test!(!)\notgood2" in the output:

"temp\development & ()\notgood2"
C:\Temp\Development & ()\NotGood2.bat

It can be seen that !test! and !Test! and the third ! in the round brackets disappear from both output strings because of !test! and !Test! are interpreted as delayed expanded variable references and there is no environment variable Test. The third ! is removed as interpreted as beginning of a delayed expanded variable reference with no matching ! marking the end of the variable name.

See also:

  • How does the Windows Command Interpreter (CMD.EXE) parse scripts?
  • Single line with multiple commands using Windows batch file
  • Where does GOTO :EOF return to?
like image 97
Mofi Avatar answered Sep 30 '22 17:09

Mofi


%~f0 causes %0 to be expanded to a fully-qualified path name. They may or may not be equivalent, depending on what the original value of %0 is.

The meanings of these modifiers are hidden in the documentation for the For command.

like image 31
Cody Gray Avatar answered Sep 30 '22 17:09

Cody Gray