Prevent batch modifiers dropping caret if it's in the filename

Viewed 64

I have a bat script and the first arg passed in is: "C:\aaa^bbb\xxx^yyy.txt"

I wish to get the file and and containing dir (head):

set winhead=%~dp1
set winfile=%~nx1
echo winhead: %winhead%
echo winfile: %winfile%

Prints

winhead: 'C:\aaabbb\'
winfile: 'xxxyyy.txt'

I see the carets ^ where dropped. Okay I will just escape them:

set Pathin=%1
set Pathin=%Pathin:^=^^%
echo Pathin: %Pathin%

Prints

Pathin: "C:\aaa^^bbb\xxx^^yyy.txt"

Now to extract filename and head:

set winhead=%~dpPathin%
set winfile=%~nxPathin%

or

set winhead=%~dpPathin
set winfile=%~nxPathin

Does not perform the modifier, but just returns the literal string. After some research I discovered the modifiers can only be used on args, i.e. %1 in this case.

So is it a bug that the modifiers don't handle carets correctly? How does one extract parts of the full path for files one may have created in explorer (i.e. those which contain carets)?

2 Answers

The ^ Circumflex Accent (so-called caret) works as an Escape character. If you need to take a caret literally in a variable, escape it using double quotes (set "winhead=%~dp1") and use it either using double quotes (echo "%winhead%") or utilizing delayed expansion (echo !winhead!).

Sample script:

@ECHO OFF
echo supplied parameters: %*
SETLOCAL EnableExtensions DisableDelayedExpansion
set "winhead=%~dp1"
set "winfile=%~nx1"
echo winhead - percent expansion: %winhead% "%winhead%" 
echo winfile - percent expansion: %winfile% "%winfile%"
SETLOCAL EnableDelayedExpansion
  echo winhead - delayed expansion: !winhead! "!winhead!"
  echo winfile - delayed expansion: !winfile! "!winfile!"
ENDLOCAL

Output: .\SO\62849275.bat "C:\aaa^bbb\xxx^yyy.txt"

supplied parameters: "C:\aaa^bbb\xxx^yyy.txt"
winhead - percent expansion: C:\aaabbb\ "C:\aaa^bbb\"
winfile - percent expansion: xxxyyy.txt "xxx^yyy.txt"
winhead - delayed expansion: C:\aaa^bbb\ "C:\aaa^bbb\"
winfile - delayed expansion: xxx^yyy.txt "xxx^yyy.txt"

You can escape a caret using an additional caret ("C:\aaa^^bbb\xxx^^yyy.txt"), or utilize call command behaviour: If the CALL command contains a caret character within a quoted string, the carets will be doubled:

CALL .\SO\62849275.bat "C:\aaa^bbb\xxx^yyy.txt"
supplied parameters: "C:\aaa^^bbb\xxx^^yyy.txt"
winhead - percent expansion: C:\aaa^bbb\ "C:\aaa^^bbb\"
winfile - percent expansion: xxx^yyy.txt "xxx^^yyy.txt"
winhead - delayed expansion: C:\aaa^^bbb\ "C:\aaa^^bbb\"
winfile - delayed expansion: xxx^^yyy.txt "xxx^^yyy.txt"

Side note. The ^ character (Circumflex Accent, U+005E) used to call caret for its visual similarity with the character ‸ (Caret, U+2038).

If you can change your input then pass "C:\aaa^^^bbb\xxx^^^yyy.txt" with the following:

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion

Set "winhead=%~dp1"
Set "winfile=%~nx1"
Echo winhead: %winhead%
Echo winfile: %winfile%

Pause

If you cannot change the input, use "C:\aaa^bbb\xxx^yyy.txt" and enable delayed expansion:

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion

Set "winhead=%~dp1"
Set "winfile=%~nx1"

SetLocal EnableDelayedExpansion
Echo winhead: !winhead!
Echo winfile: !winfile!
EndLocal

Pause
Related