通過轉義符實現設置終端輸出的顏色和顯示方式

我們在linux 上調試代碼的時候, 往往需要往終端中輸出大量的調試信息, 但是如果各個級別的調試信息文字的顏色、大小都是一樣的話, 我們往往無法一眼找到比如錯誤日志或者其他級別的日志

image

圖中只是簡單的做了個測試, 真實環境下的調試信息, 遠比配圖要復雜的多, 如果在調試某個 bug 的時候, 一下子甩出一堆文字, 要定位部分輸出, 還是很考究眼力。

有沒有什么方法能讓調試信息一目了然呢? 當然有, 而且很簡單。

在linux終端中, 字符顏色和顯示方式是由轉義序列控制的, 是文本模式下的系統顯示功能, 與具體開發語言并無關系(這就代表, 任何開發語言都能夠使用這個方法??)。

轉義序列

轉義序列以控制字符ESC開頭, 該字符的 ASCII 碼十進制表示為 27, 十六進制為 0x1B, 八進制表示為 033 。多數的轉義序列超過兩個字符, 所以通常以ESC和左括號[開頭。該起始序列稱為控制序列引導符(CSI, Control Sequence Intro), 通常由\033或者\e[代替。

通過轉義序列設置終端顯示屬性時, 可以采用下列格式

\033[ Param {;Param;...} m

或者是:

\e[ Param {;Param;...}m

其中, \033[\e[引導轉義序列, m表示設置屬性并結束轉義。Param為屬性值, {...} 表示參數是可以多選的, 多個參數之間用分號隔開, 不限制順序。

轉義序列可被控制字符 CAN(Cancel) 和 SUB(Substitute)中斷。

轉義序列相關常用參數

man console_codes 可以查看更多的參數描述

顯示:

  • 0: 默認
  • 1: 粗體/高亮
  • 22: 非粗體
  • 4: 單條下滑線
  • 24: 無下滑線
  • 5: 閃爍
  • 25: 吳閃爍
  • 7: 反顯、翻轉前景色和背景色
  • 27: 無反顯

顏色:

  • 0: 黑
  • 1: 紅
  • 2: 綠
  • 3: 黃
  • 4: 藍
  • 5: 洋紅
  • 6: 青色
  • 7: 白

前景色為 30 + 顏色值, 如31表示前景色是紅色

背景色為 40 + 顏色值, 如41表示背景色為紅色

因此, 通過轉義序列設置終端顯示屬性時, 常見格式為:

\033[顯示方式;前景色;背景色m輸出字符串\e[顯示方式;前景色;背景色m輸出字符串\e[0m

此外, 還有一些 ANSI 控制碼, 如:

  • nA(光標上移n行)
  • nB(光標下移動n行)
  • C(光標右移動n行)
  • nD (光標左移n行 )
  • 2J(清屏)
  • K(清除從光標到行尾的內容)
  • s(保存光標位置)
  • u(恢復光標位置)
  • ?25l(隱藏光標)
  • ?25l(顯示光標)
\e[0m   # 用于恢復默認終端輸出屬性, 否則影響后續輸出。

php 中實現

先把常用的屬性定義為常量, 方便后續調用:

<?php
/**
 * Created by PhpStorm.
 * User: collin
 * Date: 2017/4/17
 * Time: 下午3:45
 */
class Log {
  const DEBUG = 1;

  // 顏色
  private const NONE = "\e[0m";
  private const BLACK = "\e[0;30m";
  private const L_BLACK = "\e[1;30m";
  private const RED = "\e[0;31m";
  private const L_RED = "\e[1;31m";
  private const GREEN = "\e[0;32m";
  private const L_GREEN = "\e[1;32m";
  private const BROWN = "\e[0;33m";
  private const YELLOW = "\e[1;33m";
  private const BLUE = "\e[0;34m";
  private const L_BLUE = "\e[1;34m";
  private const PURPLE = "\e[0;35m";
  private const L_PURPLE = "\e[1;35m";
  private const CYAN = "\e[0;36m";
  private const L_CYAN = "\e[1;36m";
  private const GRAY = "\e[0;37m";
  private const WHITE = "\e[1;37m";

  // 字體
  private const BOLD = "\e[1m";
  private const UNDERLINE = "\e[4m";
  private const BLINK = "\e[5m";
  private const REVERSE = "\e[7m";
  private const HIDE = "\e[8m";
  private const CLEAR = "\e[2J";
  private const CLRLINE = "\r\e[K\" //or \"\e[1K\r";

  /**
   * 控制臺輸出 success 級別消息
   * @param $str 日志內容
   */
  static public function console_success($str) {
    echo self::GREEN . 'SUCCESS['. date('Y-m-d H:i:s', time()).']: ' . $str . self::NONE . PHP_EOL;
  }

  /**
   * 控制臺輸出 error 級別消息
   * @param $str 日志內容
   */
  static public function console_error($str) {
    echo self::RED . 'ERROR['. date('Y-m-d H:i:s', time()).']: ' . $str . PHP_EOL;
    $arr = debug_backtrace();
    echo self::format($arr);
    echo self::NONE . PHP_EOL;
  }

  /**
   * 控制臺輸出 warning 級別消息
   * @param $str 日志內容
   */
  static public function console_warning($str) {
    echo self::BROWN . 'WARNING['. date('Y-m-d H:i:s', time()).']: ' . $str . PHP_EOL;

    $arr = debug_backtrace();
    echo self::format($arr);
    echo self::NONE . PHP_EOL;
  }

  /**
   * 如果DEBUG = 1, 則輸出 debug 級別消息
   * @param $str 日志內容
   */
  static public function console_debug($str) {
    if (self::DEBUG) {
      echo self::CYAN . 'DEBUG['. date('Y-m-d H:i:s', time()).']: ' . $str . PHP_EOL;

      $arr = debug_backtrace();
      echo self::format($arr);
      echo self::NONE . PHP_EOL;
    }
  }

  /**
   * 如果 DEBUG = 1, 則遍歷對象
   * @param $arr object/array
   */
  static public function console_dump_debug($arr) {
    if (self::DEBUG) {
      echo self::CYAN . 'DEBUG dump['. date('Y-m-d H:i:s', time()).']: '. PHP_EOL;
      var_dump($arr);
      echo self::NONE . PHP_EOL;
    }
  }

  /**
   * 控制臺輸出 info 級別消息
   * @param $str 日志內容
   */
  static public function console_info($str) {
    echo self::UNDERLINE . 'INFO['. date('Y-m-d H:i:s', time()).']: ' . $str . self::NONE . PHP_EOL;
  }

  /**
   * 格式化堆棧信息
   * @param $arr
   * @return string
   */
  static private function format($arr) {
    $str = '';
    foreach ($arr as $k => $v) {
      $file = $v['file'];
      $line = $v['line'];
      $class = isset($v['class']) ? $v['class'] . '\\' : 'stdClass\\';
      $function = $v['function'] ?? '';
      $str .= "#$k  $file($line): {$class}{$function}" . PHP_EOL;
    }
    return $str;
  }
}

上面的代碼是我簡單寫的一個帶色彩的日志類。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 我們在編寫程序的時候,通常需要終端對輸出顯示紅色或者綠色等各...
    LeaderBiao閱讀 2,994評論 0 3
  • 喜歡玩Linux的人,一般都是一個愛折騰的人,哈哈~~好巧 我就是這么一個愛折騰的人。 好了,那么接下...
    四月不見閱讀 1,260評論 0 1
  • 終端的字符顏色是用轉義序列控制的,是文本模式下的系統顯示功能,和具體的語言無關,shell,python,perl...
    qianghaohao閱讀 1,423評論 0 1
  • R今天的運動會還是很熱鬧的,如果不是因為當了記者的緣故恐怕對這類比賽也是沒有興趣的吧。雖然還有些生手,以后慢慢也會...
    俗女子閱讀 238評論 0 1
  • 清晨,走出家門上班去,天空有些蒙蒙的,微風拂面,清涼,一如平靜的心,感恩之情油然而生,感恩這一天美好的開始,馬路依...
    安妮_beijing閱讀 194評論 0 0