簡體   English   中英

如何使用命令行參數來控制打印多色文本的批處理程序?

[英]How can I use command line arguments to control a batch program that prints multi-colour text?

我有一個批處理腳本,可以在命令提示符的同一行上顯示兩種或多種顏色的文本。 (以下)

@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。 然后打開命令提示符並鍵入“顏色”。 這就是我希望它運行的方式; 沒有額外的命令、安裝腳本、文件路徑; 只是一個簡單的一兩個詞函數,所有雜亂的代碼都在后台運行(看不見)。 然而,上面的想法仍然不會讓我從命令提示符指定我自己的文本或顏色......有什么想法嗎?

編輯:取 3

創建文件夾C:\\Utilities 將此文件夾添加到您的 Path 環境變量,以便 Windows 在那里查找其他腳本和命令。

  1. 打開控制面板、系統、高級系統設置(或 Windows XP 中的“高級”)、環境變量。
  2. 在“系統變量”列表中,選擇“路徑”變量。
    不要搞砸這些下一步!
  3. 按編輯。
  4. 將光標置於行尾並確保未選擇任何文本。
  5. 添加文本;C:\\Utilities ,包括分號。 不要刪除任何其他文本。
  6. 按確定。
    再次輕松呼吸。
  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"

請注意,顏色詞區分大小寫。

您可以使用批處理參數 %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"

Windows XP以來,通過使用 PowerShell 作為通過命名管道鏈接到控制台輸出的子進程,可以快速替代使用 cmd 批處理高效着色。 也可以使用 FindStr 來完成,但 PowerShell 提供了更多選項並且看起來更快。

在保持PowerShell中作為子進程,使用管進行通信的主要興趣是,顯示遠遠快於發射的PowerShell或FINDSTR為每一行顯示。

其他優點:

  • 不需要臨時文件
  • 通過管道回顯允許顯示完整的 ASCII 表而不會打擾轉義。
  • 使用 fd 重定向工作正常。 僅以標准錯誤為例,或重定向到文件/其他進程。

這是執行此操作的示例代碼:

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

這個“代碼”是在延遲擴展開啟的情況下編寫的,但可以重寫以在沒有它的情況下工作。 有很多安全點需要考慮,不要直接在野外使用

如何使用它 :

@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

鏈接到我關於同一主題的原始答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM