如何使用命令行参数来控制打印多色文本的批处理程序?

时间:2011-09-03 00:42:56

标签: function colors batch-file command

我有一个批处理脚本,可以在命令提示符的同一行显示两种或多种颜色的文本。 (下同)

@echo off
SETLOCAL EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)
echo say the name of the colors, don't read

call :ColorText 0a "blue"
call :ColorText 0C "green"
call :ColorText 0b "red"
echo(
call :ColorText 19 "yellow"
call :ColorText 2F "black"
call :ColorText 4e "white"
pause
goto :eof

:ColorText
echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1
goto :eof

但是,必须通过编辑带有记事本的批处理文件在脚本中输入该文本。我希望能够打开命令提示符并键入:

cecho /blue hello world!

cecho blue "hello world!"

或简单的地方,我可以提供颜色(最好是字符串而不是颜色代码)和文字(有或没有引号)。


我不知道这对你有用,但可以保存脚本的这一部分:

echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1
goto :eof

(从“:ColorText”到脚本的结尾) 并将其保存为“C:\ windows \ system32”中的“ColorText.bat”。然后在脚本的另一半,你看到的任何地方:

call :ColorText

将其更改为:

call ColorText

(省略冒号) 并将该脚本保存为“C:\ windows \ system32”中的colors.bat。然后打开命令提示符并键入“colors”。这就是我希望它发挥作用的方式;没有其他命令,设置脚本,文件路径;只是一个简单的单词或双字功能,所有乱码都在后台进行(看不见)。但是上面的想法仍然不允许我从命令提示符中指定我自己的文本或颜色....任何想法?

3 个答案:

答案 0 :(得分:2)

编辑:拿3

创建文件夹C:\Utilities。将此文件夹添加到Path环境变量中,以便Windows在那里查找其他脚本和命令。

  1. 打开控制面板,系统,高级系统设置(或Windows XP中的“高级”),环境变量。
  2. 在“系统变量”列表中,选择“路径”变量 不要搞砸这些后续步骤!
  3. 按编辑。
  4. 将光标放在行尾,确保没有选择任何文本。
  5. 添加文本;C:\Utilities,包括分号。请勿删除任何其他文字。
  6. 按OK 再次轻松呼吸。
  7. 根据需要多次按OK关闭所有窗口。
  8. 按照:ColorText标签后的脚本将其保存到C:\Utilities\cecho.bat。在@前放置echo off,以防止在脚本中出现echo off

    <强> CEcho.bat

    @Echo Off
    SetLocal EnableDelayedExpansion
    For /F "tokens=1,2 delims=#" %%a In ('"Prompt #$H#$E# & Echo On & For %%b In (1) Do Rem"') Do (
    Set "DEL=%%a"
    )
    <Nul Set /p ".=%DEL%" > "%~2"
    FindStr /v /a:%1 /R "^$" "%~2" Nul
    Del "%~2" > Nul 2>&1
    EndLocal
    

    现在您可以从任何命令行或脚本使用此命令。用法:

    CEcho color "text"
    

    修改:回复您的评论:

    您可以通过插入以下行并替换FindStr行来使用单词作为颜色:

    Set Color=%1
    If %1==blue Set Color=9
    If %1==red Set Color=C
    etc...
    FindStr /v /a:%Color% /R "^$" "%~2" Nul
    

    现在您可以输入:

    CEcho red "apple"
    CEcho blue "water"
    CEcho A "grass"
    CEcho 6 "dirt"
    CEcho 26 "tree"
    

    请注意,颜色词区分大小写。

答案 1 :(得分:1)

您可以使用批处理参数%1,%2,...,%n作为颜色和内容的参数

cecho 0a "hello world!"

@echo off
call :ColorText %1 "%~2"
...

如果您想使用颜色名称,则必须将它们转换为相应的数字。

cecho blue "hello"

@echo off
if "%1"=="red" set color=0c
if "%1"=="blue" set color=0b
if ...
call :ColorText %color% "%~2"

答案 2 :(得分:0)

快速替代颜色高效 cmd批处理自Windows XP,通过使用PowerShell作为通过命名链接到控制台输出的子进程管道。也可以使用 FindStr 来完成,但 PowerShell 提供了更多选项并且看起来更快。

将 PowerShell 保持为子进程并使用管道进行通信的主要目的是显示比为要显示的每一行启动 PowerShell 或 FindStr 快得多

其他优点:

  • 不需要临时文件
  • 通过管道回显允许显示完整的 ASCII 表,而无需麻烦转义。
  • 使用 fd 重定向工作正常。仅以 stderr 着色为例,或重定向到文件/其他进程。

这是一个示例代码:

::
:: Launch a PowerShell child process in the background linked to the console and 
:: earing through named pipe PowerShellCon_%PID%
::
:: Parameters :
::   [ PID ] : Console Process ID used as an identifier for the named pipe, launcher PID by default.
::   [ timeout ] : Subprocess max life in seconds, 300 by default. If -1, the subprocess
::                  will not terminate while the process %PID% is still alive.
:: Return :
::   0 if the child PowerShell has been successfully launched and the named pipe is available.
::   1 if it fails.
::   2 if we can't get a PID.
::   3 if PowerShell is not present or doesn't work.
::
:LaunchPowerShellSubProcess
  SET LOCALV_PID=
  SET LOCALV_TIMEOUT=300
  IF NOT "%~1" == "" SET LOCALV_PID=%~1
  IF NOT "%~2" == "" SET LOCALV_TIMEOUT=%~2
  powershell -command "$_" 2>&1 >NUL
  IF NOT "!ERRORLEVEL!" == "0" EXIT /B 3
  IF "!LOCALV_PID!" == "" (
    FOR /F %%P IN ('powershell -command "$parentId=(Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId; write-host (Get-WmiObject Win32_Process -Filter ProcessId=$parentId).ParentProcessId;"') DO (
      SET LOCALV_PID=%%P
    )
  )
  IF "!LOCALV_PID!" == "" EXIT /B 2
  START /B powershell -command "$cmdPID=$PID; Start-Job -ArgumentList $cmdPID -ScriptBlock { $ProcessActive = $true; $timeout=!LOCALV_TIMEOUT!; while((!LOCALV_TIMEOUT! -eq -1 -or $timeout -gt 0) -and $ProcessActive) { Start-Sleep -s 1; $timeout-=1; $ProcessActive = Get-Process -id !LOCALV_PID! -ErrorAction SilentlyContinue; } if ($timeout -eq 0 -or ^! $ProcessActive) { Stop-Process -Id $args; } } | Out-Null ; $npipeServer = new-object System.IO.Pipes.NamedPipeServerStream('PowerShellCon_!LOCALV_PID!', [System.IO.Pipes.PipeDirection]::In); Try { $npipeServer.WaitForConnection(); $pipeReader = new-object System.IO.StreamReader($npipeServer); while(($msg = $pipeReader.ReadLine()) -notmatch 'QUIT') { $disp='write-host '+$msg+';'; invoke-expression($disp); $npipeServer.Disconnect(); $npipeServer.WaitForConnection(); }; } Finally { $npipeServer.Dispose(); }" 2>NUL
  SET /A LOCALV_TRY=20 >NUL
  :LaunchPowerShellSubProcess_WaitForPipe
  powershell -nop -c "& {sleep -m 50}"
  SET /A LOCALV_TRY=!LOCALV_TRY! - 1 >NUL
  IF NOT "!LOCALV_TRY!" == "0" cmd /C "ECHO -NoNewLine|MORE 1>\\.\pipe\PowerShellCon_!LOCALV_PID!" 2>NUL || GOTO:LaunchPowerShellSubProcess_WaitForPipe
  IF "!LOCALV_TRY!" == "0" EXIT /B 1
  EXIT /B 0

这个“代码”是用延迟扩展ON编写的,但可以重写以在没有它的情况下工作。有很多安全点需要考虑,不要直接在野外使用。

如何使用:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
IF ERRORLEVEL 1 (
  ECHO Extension inapplicable
  EXIT /B 1
)
::
SETLOCAL ENABLEDELAYEDEXPANSION
IF ERRORLEVEL 1 (
  ECHO Expansion inapplicable
  EXIT /B 1
)
CALL:LaunchPowerShellSubProcess
IF NOT ERRORLEVEL 0 EXIT /B 1
CALL:Color Cyan "I write this in Cyan"
CALL:Blue "I write this in Blue"
CALL:Green "And this in green"
CALL:Red -nonewline "And mix Red"
CALL:Yellow "with Yellow"
CALL:Green "And not need to trouble with ()<>&|;,%""^ and so on..."
EXIT /B 0
:Color
ECHO -foregroundcolor %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Blue
ECHO -foregroundcolor Blue %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Green
ECHO -foregroundcolor Green %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Red
ECHO -foregroundcolor Red %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Yellow
ECHO -foregroundcolor Yellow %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
::
:: Launch a PowerShell child process in the background linked to the console and 
:: earing through named pipe PowerShellCon_%PID%
::
:: Parameters :
::   [ PID ] : Console Process ID used as an identifier for the named pipe, launcher PID by default.
::   [ timeout ] : Subprocess max life in seconds, 300 by default. If -1, the subprocess
::                  will not terminate while the process %PID% is still alive.
:: Return :
::   0 if the child PowerShell has been successfully launched and the named pipe is available.
::   1 if it fails.
::   2 if we can't get a PID.
::   3 if PowerShell is not present or doesn't work.
::
:LaunchPowerShellSubProcess
  SET LOCALV_PID=
  SET LOCALV_TIMEOUT=300
  IF NOT "%~1" == "" SET LOCALV_PID=%~1
  IF NOT "%~2" == "" SET LOCALV_TIMEOUT=%~2
  powershell -command "$_" 2>&1 >NUL
  IF NOT "!ERRORLEVEL!" == "0" EXIT /B 3
  IF "!LOCALV_PID!" == "" (
    FOR /F %%P IN ('powershell -command "$parentId=(Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId; write-host (Get-WmiObject Win32_Process -Filter ProcessId=$parentId).ParentProcessId;"') DO (
      SET LOCALV_PID=%%P
    )
  )
  IF "!LOCALV_PID!" == "" EXIT /B 2
  START /B powershell -command "$cmdPID=$PID; Start-Job -ArgumentList $cmdPID -ScriptBlock { $ProcessActive = $true; $timeout=!LOCALV_TIMEOUT!; while((!LOCALV_TIMEOUT! -eq -1 -or $timeout -gt 0) -and $ProcessActive) { Start-Sleep -s 1; $timeout-=1; $ProcessActive = Get-Process -id !LOCALV_PID! -ErrorAction SilentlyContinue; } if ($timeout -eq 0 -or ^! $ProcessActive) { Stop-Process -Id $args; } } | Out-Null ; $npipeServer = new-object System.IO.Pipes.NamedPipeServerStream('PowerShellCon_!LOCALV_PID!', [System.IO.Pipes.PipeDirection]::In); Try { $npipeServer.WaitForConnection(); $pipeReader = new-object System.IO.StreamReader($npipeServer); while(($msg = $pipeReader.ReadLine()) -notmatch 'QUIT') { $disp='write-host '+$msg+';'; invoke-expression($disp); $npipeServer.Disconnect(); $npipeServer.WaitForConnection(); }; } Finally { $npipeServer.Dispose(); }" 2>NUL
  SET /A LOCALV_TRY=20 >NUL
  :LaunchPowerShellSubProcess_WaitForPipe
  powershell -nop -c "& {sleep -m 50}"
  SET /A LOCALV_TRY=!LOCALV_TRY! - 1 >NUL
  IF NOT "!LOCALV_TRY!" == "0" cmd /C "ECHO -NoNewLine|MORE 1>\\.\pipe\PowerShellCon_!LOCALV_PID!" 2>NUL || GOTO:LaunchPowerShellSubProcess_WaitForPipe
  IF "!LOCALV_TRY!" == "0" EXIT /B 1
  EXIT /B 0

Link 我对同一主题的原始回答。