Why ~dpf ?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
sst
Posts: 93
Joined: 12 Apr 2018 23:45

Why ~dpf ?

#1 Post by sst » 02 May 2018 09:28

In various topics and codes here and there on dostips It can be seen that this code is recommended to use or have been used for getting carriage return.

Code: Select all

for /F %%Z in ('copy /Z "%~dpf0" nul') do set "CR=%%Z"
The first time I saw it, I ask myself why not just "%~f0" but "%~dpf0" ?
Then I thought batch is full of gotchas and surprises there maybe a reason behind it that is not obvious to me, so I kept using "%~dpf0"

But I'm eager to know, in general are there any circumstances where ~dpf and ~f modifiers can yield different results?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Why ~dpf ?

#2 Post by aGerman » 02 May 2018 09:56

I don't see any reason for using ~dpf rather than only ~f.

Steffen

Sponge Belly
Posts: 231
Joined: 01 Oct 2012 13:32
Location: Ireland
Contact:

Re: Why ~dpf ?

#3 Post by Sponge Belly » 19 Sep 2018 15:46

Hi sst, :)

I saw an explanation for using "%~dpf0" somewhere a long time ago. I think it was by jeb, but I could never find it again. :(

And then I noticed a subroutine you used in this SO Answer:

Code: Select all

:getBatFullPath
set "%~1=%~f0" & exit /b
You said it was a “workaround for CMD %~0 bug.” Please give an explanation/reference.

- SB

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Why ~dpf ?

#4 Post by carlos » 19 Sep 2018 18:53

The %~f0 bug is related to extra quotes.

This code is in this location: C:\edit\test.cmd

Code: Select all

@Echo Off
Setlocal EnableExtensions
Echo %~f0
Echo %~dpf0
Echo %~n0
Echo %~x0

If you call it using full path, but with extra quotes as next:

Code: Select all

C:\>""c:\edit\test.cmd""
You get:

Code: Select all

C:\"c:\edit\test.cmd"
C:\"c:\edit\test.cmd"
test
.cmd"
That is the bug, you need the fully location of your script file, but in this case you get garbage information: C:\"c:\edit\test.cmd"

Seems that %~dpf0 is not a workaround for it.
Last edited by carlos on 20 Sep 2018 09:14, edited 4 times in total.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Why ~dpf ?

#5 Post by dbenham » 19 Sep 2018 20:06

I have a vague recollection of seeing that question before years ago (I may have even asked), and no one had a reason for using %~dpf0.

There certainly is no logical reason for it, and I've never seen any odd behavior that would warrant it.


Dave Benham

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Why ~dpf ?

#6 Post by carlos » 19 Sep 2018 22:25

Other bug of %~f0 that I found here: viewtopic.php?t=5057#p29705
Is related when you change the current directory inside the script, the result is different if you called your script with quotes.

This is script is located in C:\dev\test2.cmd

Code: Select all

@echo off
Setlocal EnableExtensions
E:
Echo E:
echo %%~f0 = %~f0
echo %%~dpf0 = %~dpf0
Result:

Code: Select all

C:\dev>test2.cmd
E:
%~f0 = C:\dev\test2.cmd
%~dpf0 = C:\dev\test2.cmd

C:\dev>"test2.cmd"
E:
%~f0 = E:\test2.cmd
%~dpf0 = E:\test2.cmd

C:\dev>
As you can see run test2.cmd and "test2.cmd" produce different result.
%~dpf0 not solve the problem, and also have non sense.

According to the documentation:
%~f Expand %1 to a Fully qualified path name.
%~d Expand %1 to a Drive letter only.
%~p Expand %1 to a Path only

Thus %~dpf is like concatenate: drive letter, path only, and fully qualified path. Fully qualified path also include drive letter and path. Thus, why try concatenate it again? Seems that cmd detect this nonses and internally convert %~dpf to %~f
Last edited by carlos on 20 Sep 2018 10:31, edited 1 time in total.

sst
Posts: 93
Joined: 12 Apr 2018 23:45

Re: Why ~dpf ?

#7 Post by sst » 20 Sep 2018 00:02

Sponge Belly wrote:
19 Sep 2018 15:46
You said it was a “workaround for CMD %~0 bug.” Please give an explanation/reference.
Hi Sponge Belly,
Although carlos has described the bug, here are some more references:
This SO Q/A CMD: failure of %~d0 when CALL quotes the name of the batch file There are some good and thorough analysis and tests by dbenham, also by jeb and MC ND. Also dbenham provided a more complete and flexible function for obtaining batch file info.

And This SO Q/A What is the reason for batch file path referenced with %~dp0 sometimes changes on changing directory? Find the answer by MC ND which analysed the internal workings of the CMD to describe how and why the bug exist and why obtaining batch file info inside a function is not affected by this bug.

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Why ~dpf ?

#8 Post by carlos » 20 Sep 2018 09:04

Thanks @sst for the links.
After read I prefer the solution of the user MC ND.
Thus, the bug can be described as is not safe expand %~f0 in the main function, it should be expanded inside other function.

Code located in C:\edit\test.cmd

Code: Select all

@echo off
setlocal enableextensions enabledelayedexpansion

D: && echo Changed to drive D:

echo Setting moduleFileName in the main function
set "moduleFileName=%~f0"
echo moduleFileName: !moduleFileName!

call :getModuleFileName
echo moduleFileName: !moduleFileName!
exit /b

:getModuleFileName
echo Setting moduleFileName inside a function
Set "moduleFileName=%~f0"
goto :eof
Do the test:
C:\edit>test.cmd
Changed to drive D:
Setting moduleFileName in the main function
moduleFileName: C:\edit\test.cmd
Setting moduleFileName inside a function
moduleFileName: C:\edit\test.cmd

C:\edit>"test.cmd"
Changed to drive D:
Setting moduleFileName in the main function
moduleFileName: D:\test.cmd
Setting moduleFileName inside a function
moduleFileName: C:\edit\test.cmd

C:\edit>""test.cmd""
Changed to drive D:
Setting moduleFileName in the main function
moduleFileName: D:\"test.cmd"
Setting moduleFileName inside a function
moduleFileName: C:\edit\test.cmd

C:\edit>c:\edit\test.cmd
Changed to drive D:
Setting moduleFileName in the main function
moduleFileName: c:\edit\test.cmd
Setting moduleFileName inside a function
moduleFileName: c:\edit\test.cmd

C:\edit>"c:\edit\test.cmd"
Changed to drive D:
Setting moduleFileName in the main function
moduleFileName: c:\edit\test.cmd
Setting moduleFileName inside a function
moduleFileName: c:\edit\test.cmd

C:\edit>""c:\edit\test.cmd""
Changed to drive D:
Setting moduleFileName in the main function
moduleFileName: D:\"c:\edit\test.cmd"
Setting moduleFileName inside a function
moduleFileName: c:\edit\test.cmd
By using in the main function bad results are the next:
D:\test.cmd
D:\"test.cmd"
D:\"c:\edit\test.cmd"

But using inside other function always get the correct result:
c:\edit\test.cmd

Thus, that is a correct workaround: expand %~f0 inside a function.
Last edited by carlos on 20 Sep 2018 10:30, edited 5 times in total.

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: Why ~dpf ?

#9 Post by carlos » 20 Sep 2018 09:38

For fun, I enable the debug using the code provided by @npocmaka_ for see how cmd expand %~f0 in the main function and in other function.

EnableDebug.cmd
//code without new line at end

Code: Select all

break&(:#)
test.cmd

Code: Select all

@Echo off
Setlocal EnableExtensions
D:
Set "ModuleFileName=%~f0"
Call :getModuleFileName
Exit /b

:getModuleFileName
Set "ModuleFileName=%~f0"
Goto :Eof
results:
C:\edit>EnableDebug.cmd
Cmd: EnableDebug.cmd Type: 0
No se esperaba reak en este momento.

C:\edit>
C:\edit>test.cmd
Cmd: test.cmd Type: 0
@
Cmd: Echo Type: 0 Args: ` off'
Cmd: Setlocal Type: 0 Args: ` EnableExtensions'
Cmd: D: Type: 0
Cmd: Set Type: 0 Args: ` "ModuleFileName=C:\edit\test.cmd"'
Cmd: Call Type: 0 Args: ` :getModuleFileName'
Cmd: :getModuleFileName Type: 0
Cmd: Set Type: 0 Args: ` "ModuleFileName=C:\edit\test.cmd"'
Cmd: Goto Type: 0 Args: ` :Eof'
Cmd: Exit Type: 0 Args: ` /b'

C:\edit>"test.cmd"
Cmd: "test.cmd" Type: 0
@
Cmd: Echo Type: 0 Args: ` off'
Cmd: Setlocal Type: 0 Args: ` EnableExtensions'
Cmd: D: Type: 0
Cmd: Set Type: 0 Args: ` "ModuleFileName=D:\test.cmd"'
Cmd: Call Type: 0 Args: ` :getModuleFileName'
Cmd: :getModuleFileName Type: 0
Cmd: Set Type: 0 Args: ` "ModuleFileName=C:\edit\test.cmd"'
Cmd: Goto Type: 0 Args: ` :Eof'
Cmd: Exit Type: 0 Args: ` /b'

C:\edit>

Sponge Belly
Posts: 231
Joined: 01 Oct 2012 13:32
Location: Ireland
Contact:

Re: Why ~dpf ?

#10 Post by Sponge Belly » 23 Sep 2018 05:33

@carlos @sst

Thanks for the great explanations and links! :)

I’ll use a function to store the value of "%~f0" in a variable from now on. Just one more nonsensical Batch thing to remember! :lol:

- SB

Post Reply