【问题标题】:How can I use command line arguments to control a batch program that prints multi-colour text?如何使用命令行参数来控制打印多色文本的批处理程序?
【发布时间】:2011-09-03 00:42:56
【问题描述】:

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

@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。然后打开命令提示符并输入“颜色”。这就是我希望它发挥作用的方式;没有额外的命令、设置脚本、文件路径;只是一个简单的一两个字函数,所有杂乱的代码都在后台运行(看不见)。但是上面的想法仍然不允许我从命令提示符指定我自己的文本或颜色....有什么想法吗?

【问题讨论】:

  • 不要将自己的文件放在系统位置。您可以更改 PATH 环境变量以在您的个人资料中添加一个位置。

标签: function colors batch-file command


【解决方案1】:

编辑:参加 3

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

  1. 打开控制面板、系统、高级系统设置(或 Windows XP 中的“高级”)、环境变量。
  2. 在“系统变量”列表中,选择“路径”变量。
    不要搞乱这些后续步骤!
  3. 按编辑。
  4. 将光标置于行尾并确保未选择任何文本。
  5. 添加文本;C:\Utilities,包括分号。不要删除任何其他文本。
  6. 按 OK。
    再次轻松呼吸。
  7. 根据需要多次按 OK 关闭所有窗口。

: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"

注意颜色词区分大小写。

【讨论】:

  • 复制了上面的代码,保存为 C:\windows\system32\cecho.bat 打开命令行并输入“cecho fc hello”,什么也没有。我还尝试了几种不同的颜色(字符串格式和十六进制数字格式),但一无所获。
  • Hand:抱歉,当我发布该评论时,我没有在问题中读到那么远……我现在将其移至问题中。道歉。
  • 我刚刚尝试了您的脚本,但似乎无法正常工作。事实上,现在看,我什至无法弄清楚:ColorText 是什么意思。它的目的是什么? 编辑: 只是解决它。它不起作用,但我看到了它背后的想法。一分钟...
  • 我压缩了脚本,但你是对的,它似乎没有为文本着色。我开始认为FindStr /A simple 不起作用。
  • 如果您愿意花时间复制示例,您会发现它有效。它需要在两个文件中搜索,并且只能对文件名着色,不能对内容着色。由于它总是在文件名后附加一个冒号,因此我在内容中使用退格键将其删除。
【解决方案2】:

您可以使用批处理参数 %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"

【讨论】:

  • 所以只是为了确保我做对了,cecho 的最终脚本是什么以及语法是什么
  • 这取决于您的喜好,如果您想使用颜色名称,请使用第二个 sn-p 并添加所有颜色名称
  • 说如果我只想输入“cecho red “hello””,最终的脚本会是什么?我无法让它工作......
  • 以前用颜色代码定义一系列变量更简单快捷:set blue=1set green=2. . .set brightwhite=0F,并以这种方式使用它们:call cecho %yellow% "A message in yellow"。这些值也适用于 COLOR 命令:`color %blue%%white%。
【解决方案3】:

一种 快速 替代颜色 有效地 使用 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 我在同一主题上的原始答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2014-10-31
    • 2015-10-19
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多