Yet another implementation with almost all control characters handle.
CAUTION:
Seems the stackoverflow incorrectly handles tabulation characters (and loses other characters like \x01
or \x04
) in the copy-pasted code, so the below code might not work if you copy it directly by CTRL+C. Use the link below to directly download the scripts.
https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/echo_path_var.bat
https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/echo_pathglob_var.bat
https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/echo_var.bat
echo_path_var.bat:
@echo off
rem USAGE:
rem echo_path_var.bat <VAR> [<PREFIX> [<SUFFIX>]]
rem <VAR>: VALUE1;VALUE2;...;VALUEN
setlocal DISABLEDELAYEDEXPANSION
set "__?VAR__=%~1"
if not defined __?PREFIX__ set "__?PREFIX__=%~2"
if not defined __?SUFFIX__ set "__?SUFFIX__=%~3"
if not defined __?VAR__ exit /b 255
if not defined %__?VAR__% exit /b 1
if /i not "%__?VAR__%" == "__STRING__" (
set "__STRING__="
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!%__?VAR__%!") do endlocal & set "__STRING__=%%i"
)
call "%%~dp0%%encode\encode_pathlist_chars.bat"
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & for %%j in (%%i) do set "__STRING__=%%j" & ^
call "%%~dp0%%encode\decode_pathlist_chars.bat" & ^
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%k in ("!__?PREFIX__!!__STRING__!!__?SUFFIX__!") do endlocal & echo.%%k
exit /b 0
echo_pathglob_var.bat:
@echo off
rem USAGE:
rem echo_pathglob_var.bat <VAR> [<PREFIX> [<SUFFIX>]]
rem <VAR>: VALUE1;VALUE2;...;VALUEN
setlocal DISABLEDELAYEDEXPANSION
set "__?VAR__=%~1"
if not defined __?PREFIX__ set "__?PREFIX__=%~2"
if not defined __?SUFFIX__ set "__?SUFFIX__=%~3"
if not defined __?VAR__ exit /b 255
if not defined %__?VAR__% exit /b 1
if /i not "%__?VAR__%" == "__STRING__" (
set "__STRING__="
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!%__?VAR__%!") do endlocal & set "__STRING__=%%i"
)
call "%%~dp0%%encode\encode_pathlist_chars_glob.bat"
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & for %%j in (%%i) do set "__STRING__=%%j" & ^
call "%%~dp0%%encode\decode_pathlist_chars_glob.bat" & ^
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%k in ("!__?PREFIX__!!__STRING__!!__?SUFFIX__!") do endlocal & echo.%%k
exit /b 0
echo_var.bat:
@echo off
rem USAGE:
rem echo_var.bat <Var> [<Prefix> [<Suffix>]]
setlocal DISABLEDELAYEDEXPANSION
set "__?VAR__=%~1"
if not defined __?PREFIX__ set "__?PREFIX__=%~2"
if not defined __?SUFFIX__ set "__?SUFFIX__=%~3"
if not defined __?VAR__ exit /b 255
if not defined %__?VAR__% exit /b 1
rem safe echo
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__?PREFIX__!!%__?VAR__%!!__?SUFFIX__!") do endlocal & echo.%%i
exit /b 0
encode_pathlist_chars.bat:
@echo off
rem Encode these characters:
rem $ - encode character
rem |&()<> - control flow characters
rem '`^%!+ - escape or sequence expand characters (`+` is a unicode codepoint sequence character in 65000 code page)
rem ?* - globbing characters in the `for ... %%i in (...)` expression or in a command line
rem <space>,= - separator characters in the `for ... %%i in (...)` expression or in a command line
rem Does not encode these characters:
rem " - quotes in the `for ... %%i in (...)` expression or or in a command line
rem ; - separator characters in the `for ... %%i in (...)` expression or in a command line
rem CAUTION:
rem The delayed expansion feature must be disabled before this script call: `setlocal DISABLEDELAYEDEXPANSION`, otherwise
rem the `!` character will be expanded.
rem
rem NOTE:
rem Character `$` already does encode.
rem
if not defined __STRING__ exit /b 0
setlocal DISABLEDELAYEDEXPANSION & ^
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__STRING__:$=$24!") do endlocal & set "__STRING__=%%i"
rem NOTE: restore the quote character later
setlocal ENABLEDELAYEDEXPANSION & set "__STRING__=!__STRING__:"=$22!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & set "__STRING__=%%i"
set "__STRING__=%__STRING__:!=$21%"
call "%%~dp0encode_asterisk_char.bat" & call "%%~dp0encode_equal_char.bat"
setlocal ENABLEDELAYEDEXPANSION & ^
set "__STRING__=!__STRING__:|=$7C!" & set "__STRING__=!__STRING__:&=$26!" & set "__STRING__=!__STRING__:(=$28!" & set "__STRING__=!__STRING__:)=$29!" & ^
set "__STRING__=!__STRING__:<=$3C!" & set "__STRING__=!__STRING__:>=$3E!" & set "__STRING__=!__STRING__:'=$27!" & set "__STRING__=!__STRING__:`=$60!" & ^
set "__STRING__=!__STRING__:^=$5E!" & set "__STRING__=!__STRING__:%%=$25!" & set "__STRING__=!__STRING__:+=$2B!" & ^
set "__STRING__=!__STRING__:?=$3F!" & set "__STRING__=!__STRING__: =$20!" & set "__STRING__=!__STRING__:,=$2C!" & ^
set "__STRING__=!__STRING__:$22="!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & endlocal & set "__STRING__=%%i"
exit /b 0
encode_pathlist_chars_glob.bat:
@echo off
rem Encode these characters:
rem $ - encode character
rem |&()<> - control flow characters
rem '`^%!+ - escape or sequence expand characters (`+` is a unicode codepoint sequence character in 65000 code page)
rem <space>,= - separator characters in the `for ... %%i in (...)` expression or in a command line
rem Does not encode these characters:
rem " - quotes in the `for ... %%i in (...)` expression or or in a command line
rem ?* - globbing characters in the `for ... %%i in (...)` expression or in a command line
rem ; - separator characters in the `for ... %%i in (...)` expression or in a command line
rem CAUTION:
rem The delayed expansion feature must be disabled before this script call: `setlocal DISABLEDELAYEDEXPANSION`, otherwise
rem the `!` character will be expanded.
rem
rem NOTE:
rem Character `$` already does encode.
rem
if not defined __STRING__ exit /b 0
setlocal DISABLEDELAYEDEXPANSION & ^
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__STRING__:$=$24!") do endlocal & set "__STRING__=%%i"
rem NOTE: restore the quote character later
setlocal ENABLEDELAYEDEXPANSION & set "__STRING__=!__STRING__:"=$22!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & set "__STRING__=%%i"
set "__STRING__=%__STRING__:!=$21%"
call "%%~dp0encode_equal_char.bat"
setlocal ENABLEDELAYEDEXPANSION & ^
set "__STRING__=!__STRING__:|=$7C!" & set "__STRING__=!__STRING__:&=$26!" & set "__STRING__=!__STRING__:(=$28!" & set "__STRING__=!__STRING__:)=$29!" & ^
set "__STRING__=!__STRING__:<=$3C!" & set "__STRING__=!__STRING__:>=$3E!" & set "__STRING__=!__STRING__:'=$27!" & set "__STRING__=!__STRING__:`=$60!" & ^
set "__STRING__=!__STRING__:^=$5E!" & set "__STRING__=!__STRING__:%%=$25!" & set "__STRING__=!__STRING__:+=$2B!" & ^
set "__STRING__=!__STRING__: =$20!" & set "__STRING__=!__STRING__:,=$2C!" & ^
set "__STRING__=!__STRING__:$22="!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & endlocal & set "__STRING__=%%i"
exit /b 0
decode_pathlist_chars.bat:
@echo off
rem Decode these characters:
rem $ - encode character
rem |&()<> - control flow characters
rem '`^%!+ - escape or sequence expand characters (`+` is a unicode codepoint sequence character in 65000 code page)
rem ?* - globbing characters in the `for ... %%i in (...)` expression or in a command line
rem <space>,= - separator characters in the `for ... %%i in (...)` expression or in a command line
rem Does not decode these characters:
rem " - quotes in the `for ... %%i in (...)` expression or or in a command line
rem ; - separator characters in the `for ... %%i in (...)` expression or in a command line
rem CAUTION:
rem The delayed expansion feature must be disabled before this script call: `setlocal DISABLEDELAYEDEXPANSION`, otherwise
rem the `!` character will be expanded.
rem
rem NOTE:
rem Character `$` already does decode.
rem
if not defined __STRING__ exit /b 0
rem NOTE: restore the quote character later
setlocal DISABLEDELAYEDEXPANSION & ^
setlocal ENABLEDELAYEDEXPANSION & set "__STRING__=!__STRING__:"=$22!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & set "__STRING__=%%i"
set "__STRING__=%__STRING__:$21=!%"
setlocal ENABLEDELAYEDEXPANSION & set "__STRING__=!__STRING__:$22="!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & set "__STRING__=%%i"
setlocal ENABLEDELAYEDEXPANSION & ^
set "__STRING__=!__STRING__:$7C=|!" & set "__STRING__=!__STRING__:$26=&!" & set "__STRING__=!__STRING__:$28=(!" & set "__STRING__=!__STRING__:$29=)!" & ^
set "__STRING__=!__STRING__:$3C=<!" & set "__STRING__=!__STRING__:$3E=>!" & set "__STRING__=!__STRING__:$27='!" & set "__STRING__=!__STRING__:$60=`!" & ^
set "__STRING__=!__STRING__:$5E=^!" & set "__STRING__=!__STRING__:$25=%%!" & set "__STRING__=!__STRING__:$2B=+!" & ^
set "__STRING__=!__STRING__:$3F=?!" & set "__STRING__=!__STRING__:$2A=*!" & ^
set "__STRING__=!__STRING__:$20= !" & set "__STRING__=!__STRING__:$2C=,!" & set "__STRING__=!__STRING__:$3D==!" & set "__STRING__=!__STRING__:$24=$!" & ^
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & endlocal & set "__STRING__=%%i"
exit /b 0
decode_pathlist_chars_glob:
@echo off
rem Decode these characters:
rem $ - encode character
rem |&()<> - control flow characters
rem '`^%!+ - escape or sequence expand characters (`+` is a unicode codepoint sequence character in 65000 code page)
rem <space>,= - separator characters in the `for ... %%i in (...)` expression or in a command line
rem Does not decode these characters:
rem " - quotes in the `for ... %%i in (...)` expression or or in a command line
rem ?* - globbing characters in the `for ... %%i in (...)` expression or in a command line
rem ; - separator characters in the `for ... %%i in (...)` expression or in a command line
rem CAUTION:
rem The delayed expansion feature must be disabled before this script call: `setlocal DISABLEDELAYEDEXPANSION`, otherwise
rem the `!` character will be expanded.
rem
rem NOTE:
rem Character `$` already does decode.
rem
if not defined __STRING__ exit /b 0
rem NOTE: restore the quote character later
setlocal DISABLEDELAYEDEXPANSION & ^
setlocal ENABLEDELAYEDEXPANSION & set "__STRING__=!__STRING__:"=$22!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & set "__STRING__=%%i"
set "__STRING__=%__STRING__:$21=!%"
setlocal ENABLEDELAYEDEXPANSION & set "__STRING__=!__STRING__:$22="!"
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & set "__STRING__=%%i"
setlocal ENABLEDELAYEDEXPANSION & ^
set "__STRING__=!__STRING__:$7C=|!" & set "__STRING__=!__STRING__:$26=&!" & set "__STRING__=!__STRING__:$28=(!" & set "__STRING__=!__STRING__:$29=)!" & ^
set "__STRING__=!__STRING__:$3C=<!" & set "__STRING__=!__STRING__:$3E=>!" & set "__STRING__=!__STRING__:$27='!" & set "__STRING__=!__STRING__:$60=`!" & ^
set "__STRING__=!__STRING__:$5E=^!" & set "__STRING__=!__STRING__:$25=%%!" & set "__STRING__=!__STRING__:$2B=+!" & ^
set "__STRING__=!__STRING__:$20= !" & set "__STRING__=!__STRING__:$2C=,!" & set "__STRING__=!__STRING__:$3D==!" & set "__STRING__=!__STRING__:$24=$!" & ^
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do endlocal & endlocal & set "__STRING__=%%i"
exit /b 0
encode_asterisk_char.bat:
@echo off
rem Encode `*` character.
rem CAUTION:
rem The delayed expansion feature must be disabled before this script call: `setlocal DISABLEDELAYEDEXPANSION`, otherwise
rem the `!` character will be expanded.
rem
rem CAUTION:
rem Character `$` must be encoded separately BEFORE this script call!
rem
if not defined __STRING__ exit /b 0
setlocal DISABLEDELAYEDEXPANSION & setlocal ENABLEDELAYEDEXPANSION & if "!__STRING__!" == "!__STRING__:**=!" ( exit /b 0 ) else endlocal
:LOOP
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=1 delims=*" %%i in (".!__STRING__!") do for /F "eol= tokens=* delims=" %%j in ("!__STRING__:**=!.") do endlocal & set "__STRING__=%%i$2A%%j" & ^
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__STRING__:~1,-1!") do ^
if not "!__STRING__!" == "!__STRING__:**=!" ( endlocal & set "__STRING__=%%i" & goto LOOP ) else endlocal & endlocal & set "__STRING__=%%i"
exit /b 0
encode_equal_char.bat:
@echo off
rem Encode `=` character.
rem CAUTION:
rem The delayed expansion feature must be disabled before this script call: `setlocal DISABLEDELAYEDEXPANSION`, otherwise
rem the `!` character will be expanded.
rem
rem CAUTION:
rem Character `$` must be encoded separately BEFORE this script call!
rem
if not defined __STRING__ exit /b 0
setlocal DISABLEDELAYEDEXPANSION & ^
setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do for /F "eol= tokens=1 delims==" %%j in (".!__STRING__!") do endlocal & set "__HEAD__=%%j" & set "__TAIL__=.%%i" & ^
setlocal ENABLEDELAYEDEXPANSION & if "!__HEAD__!" == "!__TAIL__!" ( exit /b 0 ) else endlocal
set "__STRING__="
setlocal ENABLEDELAYEDEXPANSION
:LOOP
if "!__HEAD__!" == "!__TAIL__!" for /F "eol= tokens=* delims=" %%i in ("!__STRING__!!__TAIL__:~1!") do endlocal & endlocal & set "__STRING__=%%i" & exit /b 0
set "__OFFSET__=2" & set "__TMP__=!__HEAD__!" & for %%i in (65536 32768 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do if not "!__TMP__:~%%i,1!" == "" set /A "__OFFSET__+=%%i" & set "__TMP__=!__TMP__:~%%i!"
if defined __TAIL__ set "__TAIL__=!__TAIL__:~%__OFFSET__%!"
set "__STRING__=!__STRING__!!__HEAD__:~1!$3D" & ^
for /F "eol= tokens=* delims=" %%i in ("!__STRING__!") do for /F "eol= tokens=1 delims==" %%j in (".!__TAIL__!") do for /F "eol= tokens=* delims=" %%k in (".!__TAIL__!") do ^
endlocal & set "__STRING__=%%i" & set "__HEAD__=%%j" & set "__TAIL__=%%k" & setlocal ENABLEDELAYEDEXPANSION
goto LOOP
Examples:
1.
>
echo_path_var.bat PATH ` `
- To use with double quotes:
>
set __?PREFIX__=^"
set __?SUFFIX__=^"
echo_path_var.bat PATH
setlocal DISABLEDELAYEDEXPANSION
set AAA=123
rem with tabulation character
set BBB="?a/b/%%c%%!" ^; "!d! ^; e ; f" ; ; ; !AAA! ^^; g,g ;;; h h
call "%%~dp0echo_var.bat" BBB ` `
call "%%~dp0echo_path_var.bat" BBB ` `
`"?a/b/%c%!" ; "!d! ^; e ; f" ; ; ; !AAA! ^; g,g ;;; h h`
`"?a/b/%c%!" `
` "!d! ^; e ; f" `
` `
` `
` !AAA! ^`
` g,g `
` h h`
- With globbing:
set "A=c:\windows\*.exe"
call "%%~dp0echo_var.bat" A
call "%%~dp0echo_pathglob_var.bat" A
c:\windows\*.exe
c:\windows\bfsvc.exe
c:\windows\explorer.exe
c:\windows\HelpPane.exe
c:\windows\hh.exe
c:\windows\notepad.exe
c:\windows\py.exe
c:\windows\pyw.exe
c:\windows\regedit.exe
c:\windows\splwow64.exe
c:\windows\winhlp32.exe
c:\windows\write.exe
set "A=c:\windows\??.exe"
call "%%~dp0echo_var.bat" A
call "%%~dp0echo_pathglob_var.bat" A
c:\windows\??.exe
c:\windows\hh.exe
c:\windows\py.exe
Pros:
- Use the
for %%i in (...)
statement to parse a path list value to parse VALUE;VALUE
the same way as "VALUE";"VALUE"
.
- Prints spaces and tabulation characters as is.
- Ignores sequence of
;
(ex: ;;;
) and treats it a single character.
- Can use globbing or print as is, no need to escape (in windows a path should not contain
*
and ?
characters).
Cons:
- Needs to separately trim leading and trailing white space characters.
$env:path.split(";")
powershell -Command ($env:Path).split(';')
. To make it still more readable, you can add sorting:powershell -Command ($env:Path).split(';') | sort