Search code examples
batch-filesublimetext3doskey

`^&` and `$T` in doskey behave similar but not same


I want to open a file in cmd and edit it in Sublime Text's specific group, so I create a doskey like this

rem version 1, ^&
doskey st="path_to\Sublime Text 3\sublime_text" --command "focus_group { \"group\": $1 }" ^& "path_to\Sublime Text 3\sublime_text" $2
rem version 2, $T
doskey st="path_to\Sublime Text 3\sublime_text" --command "focus_group { \"group\": $1 }" $T "path_to\Sublime Text 3\sublime_text" $2

The command before ^& or $T will focus ST on group $1 you want, command after ^& or $T will open the file $2

Then in cmd

>>> rem version 1, ^&
>>> st 0 test.py & rem press enter
>>>
----------------------------------
>>> rem version 2, $T
>>> st 0 test.py & rem press enter, one more prompt compare version 1
>>>
>>>

Another try

rem alias.bat in C:\Windows\System32, work like alias in linux
doskey lscd1=dir ^& cd ..
doskey lscd2=dir $T cd ..

Result

path1\path2> lscd1
Volume in drive C is OS
 Volume Serial Number is DA7D-663C

 Directory of path2

11/24/2019  09:45 PM   0 test.py
path1>
---------------------------------
path1\path2> lscd2
Volume in drive C is OS
 Volume Serial Number is DA7D-663C

 Directory of path2

11/24/2019  09:45 PM   0 test.py
path1\path2>
path1>

The Doc of $T is

$T or $t Separates commands. Use either of these special characters to separate commands when you create macros or type commands on the doskey command line. These special characters are equivalent to using the ampersand (&) on a command line.

I guess ^& is 'escape the ampersand', why these two behave differently?


Solution

  • Interesting, I never noticed the difference before.

    When using $T the macro issues each command separately to cmd.exe, each one getting its own prompt. However, the subsequent commands are not echoed to the screen, so it looks kind of odd.

    For example:

    C:\test>doskey $T=echo command 1 $T echo command 2
    
    C:\test>$T
    command 1
    
    C:\test>command 2
    
    C:\test>
    

    When you use ^& doskey treats the entire construct as a single command that is passed to cmd.exe all at once, so you don't get any extra prompts. Note that the ^ is consumed during the definition phase so that only & is stored in the definition, not ^&.

    C:\test>doskey amp=echo command 1 ^& echo command 2
    
    C:\test>amp
    command 1
    command 2
    
    C:\test>
    

    You can get $T output to look like ^& if you add echo off and echo on before and after your main definition

    C:\test>doskey $T2=echo off $T echo command 1 $T echo command 2 $T echo on
    
    C:\test>$T2
    command 1
    command 2
    
    C:\test>
    

    If I were to use doskey macros, then I would prefer to use ^&. But I rarely use them because they have severe limitations:

    • They do not execute when used within batch scripts
    • They do not execute when combined with pipes
    • They do not execute when used with FOR /F %A in ('macro') do ...
    • They do not execute when combined with any of the concatenation operators &, &&, or ||

    UPDATE

    When I say that $T causes each command to get its own prompt, that means that each command gets parsed separately. This has a potential advantage in that your macro can set variable var and then later on access the value %var% without having to use delayed expansion. When using ^& all commands are parsed at once, so you can't use %var%.

    Here is a silly example showing how you can't use %v% with ^& but you can use %v% with $T

    C:\test>set "v="
    
    C:\test>doskey m1=set "v=OK" ^& echo v=%v% - doesn't work with ^^^^^^^& ^& set "v="
    
    C:\test>m1
    v=%v% - doesn't work with ^&
    
    C:\test>doskey m2=set "v=OK" $T echo v=%v% - works with $^^T $T set "v="
    
    C:\test>m2
    
    C:\test>v=OK - works with $T
    
    C:\test>
    

    A more practical example would be a macro that executes a command then does something based on the resultant %errorlevel%.