'漂亮打印'窗口%PATH%变量 - 如何拆分';'在CMD shell中

时间:2011-03-29 11:09:26

标签: windows batch-file path

我想在Windows CMD提示符中运行一个简单的单行程序来打印我的%PATH%变量,每行一个条目。

我试过这个:for /f "delims=;" %a in ("%path%") do echo %a但这只打印第一个条目:

Z:\>for /f "delims=;" %a in ("%path%") do echo %a

Z:\>echo c:\python25\.
c:\python25\.

从上面的输出中可以看出,这也是打印echo %a命令以及输出。有没有办法阻止这个?

如果我尝试类似的命令,我会收到所有条目,但仍会得到echo %a输出垃圾邮件的结果。我不明白为什么以下打印所有条目,但我对%PATH%的尝试没有。我怀疑我不理解/F开关。

Z:\>for %a in (1 2 3) do echo %a

Z:\>echo 1
1

Z:\>echo 2
2

Z:\>echo 3
3

11 个答案:

答案 0 :(得分:68)

简单的方法是使用

for %a in ("%path:;=";"%") do @echo %~a

这适用于路径中没有;并且单个元素周围没有"的所有人 测试路径= C:\ qt \ 4.6.3 \ bin; C:\ Program Files; C:\ documents&设置

但“总是”解决方案有点复杂 编辑:现在是一个有效的变体

@echo off
setlocal DisableDelayedExpansion
set "var=foo & bar;baz<>gak;"semi;colons;^&embedded";foo again!;throw (in) some (parentheses);"unmatched ;-)";(too"

set "var=%var:"=""%"
set "var=%var:^=^^%"
set "var=%var:&=^&%"
set "var=%var:|=^|%"
set "var=%var:<=^<%"
set "var=%var:>=^>%"

set "var=%var:;=^;^;%"
rem ** This is the key line, the missing quote is intended
set var=%var:""="%
set "var=%var:"=""%"

set "var=%var:;;="";""%"
set "var=%var:^;^;=;%"
set "var=%var:""="%"
set "var=%var:"=""%"
set "var=%var:"";""=";"%"
set "var=%var:"""="%"

setlocal EnableDelayedExpansion
for %%a in ("!var!") do (
    endlocal
    echo %%~a
    setlocal EnableDelayedExpansion
)

我在那里做了什么? 我试图解决主要问题:引号内的分号应该被忽略,只有普通分号应该被";"替换

我使用批处理解释器本身来解决这个问题。

  • 首先,我必须使字符串安全,转义所有特殊字符。
  • 然后所有;都替换为^;^;
  • 然后技巧从行
    开始 set var=%var:"=""%"(缺少的引用是关键!) 这扩展的方式是所有逃脱的角色都会失去它们的逃脱插入符:
    var=foo & bar;;baz<>gak;;"semi^;^;colons^;^;^&embedded";;foo again!;; ...
    但仅限于引号之外,所以现在引号;;^;^;内的分号之间存在差异。
    这是关键。

答案 1 :(得分:64)

一个简单的衬垫,可以打印PATH环境变量:

ECHO.%PATH:;= & ECHO.%

如果您的PATH等于A;B;C,则上述字符串替换会将其更改为ECHO.A & ECHO.B & ECHO.C并一次性执行所有操作。完全停止可防止出现“ECHO已开启”消息。

答案 2 :(得分:10)

对Stephan Quan非常聪明的单线解决方案的更新:我遇到的问题是尾随的分号 - (也许是两个连续的分号,即空路径元素)会导致消息& #34; ECHO开启了#34;出现。我通过在第二个ECHO语句之后插入一个句点来解决这个问题(这是抑制ECHO开启/关闭消息的语法)。但是,它会产生一个额外的空行:

ECHO %PATH:;= & ECHO.%

答案 3 :(得分:8)

我对jeb聪明的“永远”解决方案进行了一些小改进。目前,jeb的解决方案存在以下问题:

  1. 如果前导路径用引号括起来,那么第一个输出 以“”
  2. 开头
  3. 如果尾随路径用引号括起来,那么最后一个输出 以“”结尾。
  4. 如果任何路径包含无害但无功能的连续“”, 然后输出保留“”
  5. 如果var包含连续的;;分隔符然后输出 ECHO关闭
  6. 此解决方案修复了小问题,而且它使用了2个更少的替换。我还消除了循环中不必要的重复启用/禁用延迟扩展。 (编辑于2011-10-30简化了ENDLOCAL逻辑)

    @echo off
    setlocal DisableDelayedExpansion
    set "var=%var:"=""%"
    set "var=%var:^=^^%"
    set "var=%var:&=^&%"
    set "var=%var:|=^|%"
    set "var=%var:<=^<%"
    set "var=%var:>=^>%"
    set "var=%var:;=^;^;%"
    set var=%var:""="%
    set "var=%var:"=""Q%"
    set "var=%var:;;="S"S%"
    set "var=%var:^;^;=;%"
    set "var=%var:""="%"
    setlocal EnableDelayedExpansion
    set "var=!var:"Q=!"
    for %%a in ("!var:"S"S=";"!") do (
      if "!!"=="" endlocal
      if %%a neq "" echo %%~a
    )
    

    如果要查看连续产生的每个空路径的空白行;分隔符,然后FOR循环的最后一行可以简单地读取echo(%%~a

    或者使用以下方式将空路径显示为“”可能更为明显:
    if %%a=="" (echo "") else echo %%~a

    各种空路径修复也适用于jeb的简单解决方案。


    更新:这是一个简单的单行使用JREPL.BAT

    您可以使用我的JREPL.BAT regular expression text processing utility来实现简单,非常强大的解决方案。 JREPL.BAT是纯脚本(混合JScript /批处理),可以在XP之后的任何Windows机器上本机运行。

    jrepl "([^;\q]+|\q.*?(\q|$))+" $0 /x /jmatch /s path
    

答案 4 :(得分:2)

Stephen Quan's answer更短更好,但这是一个Python解决方案:

python -c "import os; print os.environ['PATH'].replace(';', '\n');"

;个分号转换为\n个换行符。

答案 5 :(得分:1)

我知道这是旧的,但是FWIW;由于某种原因,我总是想要这个。前段时间,我给自己写了一个脚本来做这件事。我对它进行了一些修饰并将其发布在我的博客上。

随意使用它。

它叫做epath,文件位于inzi.com。它被编译为EXE以便于使用(使用vbsedit):here

你可以在那里下载exe。如果您希望将其作为vbs脚本,那么这是脚本的源代码。

    scriptname = Wscript.ScriptName 'objFSO.GetFileName(WScript.FullName)

    Function BubbleSort(arrData,strSort)
    'borrowed from here: http://vbscripter.blogspot.com/2008/03/q-how-do-i-sort-data-in-array.html

    'Input: arrData = Array of data.  Text or numbers.
    'Input: strSort = Sort direction (ASC or ascending or DESC for descending)
    'Output: Array
    'Notes: Text comparison is CASE SENSITIVE
    '        strSort is checked for a match to ASC or DESC or else it defaults to Asc


        strSort = Trim(UCase(strSort))
        If Not strSort = "ASC" And Not strSort = "DESC" Then
            strSort = "ASC"
        End If 

        For i = LBound(arrData) to UBound(arrData)
          For j = LBound(arrData) to UBound(arrData)
            If j <> UBound(arrData) Then
                If strSort = "ASC" Then
                  If UCase(arrData(j)) > UCase(arrData(j + 1)) Then
                     TempValue = arrData(j + 1)
                     arrData(j + 1) = arrData(j)
                     arrData(j) = TempValue
                  End If
                End If

                If strSort = "DESC" Then
                    If UCase(arrData(j)) < UCase(arrData(j + 1)) Then
                        TempValue = arrData(j + 1)
                        arrData(j + 1) = arrData(j)
                        arrData(j) = TempValue
                     End If        
                End If 
            End If
          Next
        Next

        BubbleSort = arrData

    End Function

    If Wscript.Arguments.Count>0 Then

        Set args = Wscript.Arguments

        bInLines = False
        bInAlphabetical = False
        bReverseSort = False
        bShowHelp = False

        For Each arg In args
            Select Case arg
                Case "-l"
                    bInLines = True
                Case "-a"
                    bInAlphabetical = True
                Case "-r"
                    bReverseSort = True
                Case Else
                    bShowHelp=True
            End Select  

        Next

        If bInLines = False Then
            bShowHelp=True
        End if

        If bShowHelp Then

                    sTxt = sTxt + "" & vbCrLf
                    sTxt = sTxt +  scriptname  & " Displays the system path in optionally friendly formats." & vbCrLf
                    sTxt = sTxt +  "ePath is helpful when viewing the system path and easily identifying folders therein." & vbCrLf
                    sTxt = sTxt + "" & vbCrLf
                    sTxt = sTxt + "EPATH [-l] [-a] [-r]" & vbCrLf
                    sTxt = sTxt + "" & vbCrLf
                    sTxt = sTxt + "Switches:" & vbCrLf
                    sTxt = sTxt + vbTab + "[-l]" + vbtab + "Show the path broken out in lines" & vbCrLf
                    sTxt = sTxt + vbtab + "[-a]" + vbTab + "Sort the path broken out in lines sorted alphabetically" & vbCrLf
                    sTxt = sTxt + vbtab + "[-r]" + vbTab + "Reverse the alphabetic sort [asc default] (ignored without -a)" & vbCrLf
                    sTxt = sTxt + "" & vbCrLf
                    sTxt = sTxt + vbTab + "Examples:" & vbCrLf
                    sTxt = sTxt +  vbTab + vbTab + scriptname  & vbTab & "(Show %PATH% normally)" & vbCrLf
                    sTxt = sTxt +  vbTab + vbTab + scriptname  & " -l" & vbCrLf
                    sTxt = sTxt +  vbTab + vbTab + scriptname  & " -l -a" & vbCrLf
                    sTxt = sTxt +  vbTab + vbTab + scriptname  & " -l -a -r" & vbCrLf
                    sTxt = sTxt +  vbTab + vbTab + scriptname  & " -? Display help (what you are seeing now)" & vbCrLf
                    sTxt = sTxt + "" & vbCrLf
                    sTxt = sTxt + "More info or questions at http://inzi.com" & vbCrLf


                    Wscript.Echo sTxt

                    WScript.Quit

        Else
            Set wshShell = CreateObject( "WScript.Shell" )
            sPath = wshShell.ExpandEnvironmentStrings( "%PATH%" )
            thePath = Split(sPath,";")

            If bInAlphabetical Then
                If bReverseSort Then
                    sDirection = "DESC"
                End If

                thePath = BubbleSort(thePath, sDirection)
            End if


            For Each item In thePath
                WScript.Echo item
            Next
            Set wshShell = Nothing
        End if
    Else
        'Nothing, echo the path.

        Set wshShell = CreateObject( "WScript.Shell" )
        WScript.Echo wshShell.ExpandEnvironmentStrings( "%PATH%" )
        Set wshShell = Nothing

    End If

答案 6 :(得分:1)

@ROMANIA_engineer在评论中提出了一个PowerShell解决方案。由于问题要求在CMD shell中运行的命令,这里有一种方法可以使用OP所需环境中的优雅代码:

powershell -Command ($env:Path).split(';')

为了使其更具可读性,您可以添加排序:

powershell -Command ($env:Path).split(';') | sort

信用:https://stackoverflow.com/a/34920014/704808

答案 7 :(得分:1)

这是一个注释良好的脚本,该脚本分析以分号分隔的项目列表,有关每个项目的可选报价,甚至允许其中包含分号的项目(引用时)。由于它利用goto循环,虽然它可能不是最快的方法,但对于特殊字符应该是安全的:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define semicolon-separated list here (sample taken from https://stackoverflow.com/a/5472168):
set "BUFFER=foo & bar;baz<>gak;"semi;colons;^&embedded";foo again!;throw (in) some (parentheses);"unmatched ;-)";(too"

setlocal EnableDelayedExpansion
echo BUFFER: !BUFFER!
echo/
endlocal

rem // Initialise items counter and clear (pseudo-)array variable:
set /A "IDX=0" & for /F "delims==" %%V in ('set $ITEM[ 2^> nul') do set "%%V="
rem // Utilise a `goto` loop to retrieve all items:
:PARSE_LOOP
rem // Check for availability of further items:
if defined BUFFER (
    rem // Increment items counter:
    set /A "IDX+=1"
    rem // Toggle delayed expansion to avoid troubles with `!`:
    setlocal EnableDelayedExpansion
    rem // Put current items counter into a `for` meta-variable:
    for %%I in (!IDX!) do (
        rem // Check whether current item begins with `"`, hence it is quoted:
        if "!BUFFER:~,1!" == ""^" (
            rem /* This point is reached when current item is quoted, hence
            rem    remove the opening `"` and split off everything past the
            rem    next one (that is the closing `"`) from the items buffer: */
            for /F tokens^=1*^ delims^=^"^ eol^=^" %%A in (";!BUFFER:~1!") do (
                endlocal
                rem // Store current item into array in unquoted manner:
                set "$ITEM[%%I]=%%A" & setlocal EnableDelayedExpansion
                for /F "delims=" %%C in ("$ITEM[%%I]=!$ITEM[%%I]:~1!") do (
                    endlocal & set "%%C" & if not defined $ITEM[%%I] set /A "IDX-=1"
                )
                rem /* Transfer remaining items beyond `endlocal` barrier;
                rem    note that a delimiters-only line still causes `for /F`
                rem    to iterate when there is just `tokens=*`: */
                for /F "tokens=* delims=;" %%D in (";%%B") do set "BUFFER=%%D"
                setlocal EnableDelayedExpansion
            )
        ) else (
            rem /* This point is reached when current item is not quoted,
            rem    hence split items string at next semicolon `;`: */
            for /F "tokens=1* delims=;" %%A in ("!BUFFER!") do (
                endlocal
                rem // Store current (unquoted) item into array:
                set "$ITEM[%%I]=%%A"
                rem // Transfer remaining items beyond `endlocal` barrier:
                set "BUFFER=%%B"
                setlocal EnableDelayedExpansion
            )
        )
    )
    endlocal
    rem // Loop back to retrieve next item:
    goto :PARSE_LOOP
)
rem // Return all retrieved items:
setlocal EnableDelayedExpansion
for /L %%I in (1,1,%IDX%) do echo ITEM %%I: !$ITEM[%%I]!
endlocal

echo/
echo INFO:   %IDX% items
echo ERROR:  %ErrorLevel%

endlocal
exit /B

答案 8 :(得分:1)

原始版本

这是一种仅执行几次字符替换的方法,该方法可以正确处理以分号分隔的可选引用项目列表,这些项目在被引用时甚至可以自己包含分号。空列表项也可以正确处理。成功的关键是能够区分引号内的分号(属于列表项)和不区分号的分号(构成分隔符):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define semicolon-separated list here (sample taken from https://stackoverflow.com/a/5472168):
set "BUFFER=foo & bar;baz<>gak;"semi;colons;^&embedded";foo again!;throw (in) some (parentheses);"unmatched ;-)";(too"
rem set "BUFFER="caret ^^";"bang !";"caret ^^ bang !""

set BUFFER & echo/

setlocal EnableDelayedExpansion
rem // Replace `^` by `^@` to avoid sequences of `^`:
set "BUFFER=!BUFFER:^=^@!"

rem // Escape special characters `^`, `&`, `<`, `>`, `|`:
set "BUFFER=!BUFFER:^=^^!"
set "BUFFER=!BUFFER:&=^&!"
set "BUFFER=!BUFFER:<=^<!"
set "BUFFER=!BUFFER:>=^>!"
set "BUFFER=!BUFFER:|=^|!"

rem // Escape `;`:
set "BUFFER=!BUFFER:;=^;!"

rem // Expand immediately, so escaping is processed for unquoted portions:
endlocal & set ^"BUFFER=%BUFFER%^"
setlocal EnableDelayedExpansion

rem // Escape `^`, `&`, `<`, `>`, `|`, hence quoted portions become double-escaped:
set "BUFFER=!BUFFER:^=^^!"
set "BUFFER=!BUFFER:&=^&!"
set "BUFFER=!BUFFER:<=^<!"
set "BUFFER=!BUFFER:>=^>!"
set "BUFFER=!BUFFER:|=^|!"

rem /* Replace `^^^` by `^` in order to resolve double-escaping;
rem    at this point, quoted `;` are represented by the sequence `^^;`: */
set "BUFFER=!BUFFER:^^^=^!"

rem // Escape `"`, so everything appears unquoted then:
set "BUFFER=!BUFFER:"=^^"!"

rem /* Expand immediately, so escaping is again processed;
rem    at this point, originally quoted `;` are represented by `^;`: */
set "BUFFER=!BUFFER:^=^^^!"
set ^"BUFFER=%BUFFER:!=^^!%^" !

rem // Remove all `"` from string:
set "BUFFER=!BUFFER:"=!^"

rem // Enclose whole string in `""` and replace each `;` by `";"`:
set ^"BUFFER="!BUFFER:;=";"!"^"

rem // Replace `^";"` (which are originally quoted `;`) by `;`:
set "BUFFER=!BUFFER:^";"=;!"

rem // Finally revert initial replacement of `^` by `^@`:
set "BUFFER=!BUFFER:^@=^!"

set BUFFER & echo/

rem // Eventually return the list items:
for %%I in (!BUFFER!) do (
    if "!!"=="" endlocal & rem // (technique taken from https://stackoverflow.com/a/7940444)
    echo(%%~I
)

endlocal
exit /B

改进版本

这是一种改进的方法,它执行较少的替换:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define semicolon-separated list here:
set "BUFFER="caret ^^";"bang !";"caret ^^; ^& bang !";caret ^;bang !;caret ^@ & bang !"

set BUFFER & echo/

setlocal EnableDelayedExpansion
rem // Replace `^` by `^@` to avoid sequences of `^`:
set "BUFFER=!BUFFER:^=^@!"

rem // Double-escape special characters `^`, `&`, `<`, `>`, `|`:
set "BUFFER=!BUFFER:^=^^^^!"
set "BUFFER=!BUFFER:&=^^^&!"
set "BUFFER=!BUFFER:<=^^^<!"
set "BUFFER=!BUFFER:>=^^^>!"
set "BUFFER=!BUFFER:|=^^^|!"

rem // Replace `;` by `^^;`:
set "BUFFER=!BUFFER:;=^^;!"

rem // Expand immediately, so escaping is processed for unquoted portions:
endlocal & set ^"BUFFER=%BUFFER%^"
setlocal EnableDelayedExpansion

rem /* Replace `^^^` by `^` in order to resolve double-escaping; at this point,
rem    quoted `;` are represented by the sequence `^^;`, unquoted ones by `^;`: */
set "BUFFER=!BUFFER:^^^=^!"

rem // Escape `"`, so everything appears unquoted then:
set "BUFFER=!BUFFER:"=^^"!"

rem /* Expand immediately, so escaping is again processed;
rem    at this point, originally quoted `;` are represented by `^;`: */
set "BUFFER=!BUFFER:^=^^^!"
set ^"BUFFER=%BUFFER:!=^^!%^" !

rem // Remove all `"` from string:
set "BUFFER=!BUFFER:"=!^"

rem // Enclose whole string in `""` and replace each `;` by `";"`:
set ^"BUFFER="!BUFFER:;=";"!"^"

rem // Replace `^";"` (which are originally quoted `;`) by `;`:
set "BUFFER=!BUFFER:^";"=;!"

rem // Finally revert initial replacement of `^` by `^@`:
set "BUFFER=!BUFFER:^@=^!"

set BUFFER & echo/

rem // Eventually return the list items:
for %%I in (!BUFFER!) do (if "!!"=="" endlocal) & echo(%%~I

endlocal
exit /B

答案 9 :(得分:0)

这在Windows上使用Git Bash在cmd窗口中有效:

echo -e ${PATH//:/\\n}

您还可以在.bash_profile中使用方便的别名:

alias showpath='echo -e ${PATH//:/\\n}'

答案 10 :(得分:0)

此脚本将使用JREPL.bat将当前Windows路径解析为txt文件。 灵感来自dbenham的上述帖子。

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

:::: THIS SCRIPT WILL PARSE THE CURRENT WINDOWS PATH INTO AT TXT FILE ::::
:::: EACH FOLDER FOUND IN PATH WILL BE ON A SEPARATE LINE ::::

:::: SCRIPT INSTRUCTIONS ::::
:: PLACE JREPL.bat IN C:\WINDOWS\SYSTEM32 FOLDER OR CUSTOM LOCATION OF YOUR CHOOSING ::
:: IF PLACED IN CUSTOM FOLDER YOU MUST LINK IT TO WINDOWS PATH ::
:: YOU CAN ACCESS WINDOWS PATH BY RUNNING THE BELOW COMMAND IN CMD.EXE ::
:: Rundll32 sysdm.cpl,EditEnvironmentVariables ::
:: DOWNLOAD JREPL.bat https://www.dostips.com/forum/viewtopic.php?t=6044 ::

:: SET WORKING DIRECTORY ::
CD /D "C:\WINDOWS\SYSTEM32"

:: UNCOMMENT LINE BELOW AND SET YOUR JREPL.bat SAVED FOLDER PATH IF YOU HAVE A BACKUP COPY ::
:: SET JOUT=<FOLDER PATH>

:: SET OUTPUT FILE ::
    SET FOUT=%USERPROFILE%\DESKTOP\PARSE.TXT

:: SET FILE TO SEARCH FOR ::
:: THIS SEARCHES FOR JREPL.BAT IN THE CURRENT WORKING DIR ::
    SET I=JREPL.BAT

:: SET CONTROL FILE TO CHECK AGAINST ::
:: THIS IS FOR DEBUGGING PURPOSES AND SHOULD NOT BE CHANGED OTHERWISE ::
    SET J=JREPL.BAT

:::: START SCRIPT ::::
    SET RESULT=
    FOR /F "DELIMS=" %%A IN ('DIR /B /O:N ^| FINDSTR /S /I "%I%" %TMP_RESULT_FILE%') DO (
    SET RESULT=%%A
    )

IF /I !RESULT! EQU %J% (
ECHO !RESULT! ^^!^^!EXISTS^^!^^!
    TIMEOUT 3 >NUL
    CALL :FOUND
    GOTO END
) ELSE (
    GOTO NOTFOUND
)
    GOTO ERROR

:FOUND
    FOR %%G IN (%I%) DO (
    %%G "([^;\Q]+|\Q.*?(\Q|$))+" $0 /X /JMATCH /S PATH>>%FOUT%
    CLS && ECHO.
ECHO %I% ^^!^^!EXECUTED SUCCESSFULLY^^!^^!
    TIMEOUT /T 3 >NUL
    EXPLORER "%FOUT%"
    GOTO END
( ELSE )
    GOTO ERROR
)

:NOTFOUND
    ECHO %I% ^^!^^!NOT FOUND^^!^^!
    TIMEOUT 3 >NUL
    CLS && ECHO.
:: UNCOMMENT THE LINES BELOW TO OPEN JREPL.BAT SAVE FOLDER IF AVAILABLE ::
    :: ECHO ^^!^^!OPENING^^!^^! %I%'S SAVED FOLDER
  :: TIMEOUT 3 >NUL
    :: EXPLORER "%JOUT%"
  GOTO END
    ( ELSE )
    GOTO ERROR
    )

:ERROR
    CLS && ECHO.
    ECHO ^^!^^!ERROR RUNNING^^!^^! %I%
    TIMEOUT 3 >NUL
    CLS && ECHO.
    ECHO ^^!^^!PLEASE FIX SCRIPT^^!^^! ::::::::::::::::::
    TIMEOUT 3 >NUL

:END
    ENDLOCAL && EXIT /B