2017-04-15 23 views
1

我嘗試寫各種造型選項,允許着色和使用重定向造型慶典的彩色輸出庫。擊試驗,怪異的行爲

例如

echo "Red" | red輸出紅色文本

echo "Bold" | bold輸出粗體文字

echo "Yellow bold" | yellow | bold輸出大膽的黃色文字

我寫了到目前爲止的代碼如下:

#shellcheck shell=bash 

# set debug 
# set -o xtrace 

# number of colors supported 
__colors=$(tput colors 2> /dev/null) 
# colors 
__black="$(tput setaf 0)" 
__red="$(tput setaf 1)" 
__green="$(tput setaf 2)" 
__yellow="$(tput setaf 3)" 
__blue="$(tput setaf 4)" 
__magenta="$(tput setaf 5)" 
__cyan="$(tput setaf 6)" 
__white="$(tput setaf 7)" 
# style 
__default="$(tput sgr0)" 
__bold="$(tput bold)" 
__underline="$(tput smul)" 


function has_colors() { 
    COLOR=${COLOR:-auto} 
    if [[ $COLOR = 'never' ]]; then 
    return 1 
    elif [[ $COLOR = 'always' ]]; then 
    return 0 
    else 
    # check if stoud is terminal and terminal supports colors 
    [[ -t 1 ]] && \ 
    [[ -n $__colors ]] && \ 
    [[ $__colors -ge 8 ]] 
    fi 
} 

function __style() { 
    read -r input 
    if has_colors; then 
    echo -e "$1" "$input" "$__default" 
    else 
    echo -e "$input" 
    fi 
} 

function black() { 
    __style "$__black" 
} 

function red() { 
    __style "$__red" 
} 

function green() { 
    __style "$__green" 
} 

function yellow() { 
    __style "$__yellow" 
} 

function blue() { 
    __style "$__blue" 
} 

function magenta() { 
    __style "$__magenta" 
} 

function cyan() { 
    __style "$__cyan" 
} 

function white() { 
    __style "$__white" 
} 

function bold() { 
    __style "$__bold" 
} 

function underline() { 
    __style "$__underline" 
} 

設置COLOR =總是與轉義碼輸出所有的時間。另一方面,COLOR = auto會執行一些檢查,以確保當前stdout是終端並且終端支持顏色。

這個問題可以用多種造型方案似乎並不被working.It總是適用的最後一個造型的選擇。例如:

echo "Yellow bold" | yellow | bold輸出大膽的文字,而不是黃色的。

在另一方面:

echo "Bold yellow" | bold | yellow輸出黃色文字,而不是大膽。

有趣的是,設置COLOR =總是好像工作得很好。所以它看起來像我執行的測試,看看標準輸出是否是終端[[ -t 1 ]]正在造成這種情況。我不確定是否因爲測試有某種延遲。但是當我刪除[[ -t 1 ]]位時,它可以工作。

任何想法,我怎麼能做到這一點?不是Bash的專家,或者shell如何處理這個問題。很困惑在這裏。

+1

的問題是,在'黃色|粗體','黃色'的標準輸出不是tty。而不是檢查每個顏色函數,你應該在主腳本中檢查一次,並設置一個變量,所有函數使用 –

+0

@這個人,這正是我檢查它的原因。如果我檢查一次並將輸出重定向到一個文件,它將與顏色轉義碼一起使用。我不想要 – Bren

+0

看着set -xv輸出,你的問題似乎來自這樣一個事實,即粗體(假設它是第二個)在樣式中的echo -e行之前被調用並接收到原始字符串的副本,因此,您可以在中間進行儘可能多的更改,並且結果始終爲標準文本粗體。不知何故,你需要讓每個管道依次接收數據(不確定最佳方法)。你可以看看等待命令? – grail

回答

0

望着這與清醒的頭腦,我發現我的方法的問題。

[[ -t 1 ]]測試如果stdout是終端中,當我管2之類的函數echo "Hello" | yellow | bold[[ -t 1 ]]通過功能yellow去時是假,表示輸出不是終端。

這是因爲函數(黃色)的輸出傳送到第二函數(粗體)。這就是爲什麼它不輸出黃色的轉義碼,只是輸出輸入。

所以,如果我一直管到另一個函數一樣echo "Hello" | yellow | bold | underline只會強調輸出。

這似乎與色彩輸出的一個很好的和簡單的方法,但現在我不得不改變我的做法,除非有辦法知道當前正在運行的功能正在被管道而不是重定向?

EDIT

This post示出有一種方法,如果命令被重定向或被管道輸送到檢測。

不過到底這種做法似乎並不十分可行的,因爲如果我當管道輸送到另一個命令是不是另一個輸出造型功能的管道將輸出的顏色代碼時,不要禁用顏色;這也許邊緣的情況下,但仍解決方案不是100%防故障

編輯解決方案:

改變了做法。取而代之的管道格式此起彼伏使用next格式選項作爲參數傳遞給第一個象下面這樣的伎倆

echo "Hello" | yellow bold underline

最終代碼如下:

#shellcheck shell=bash 

# set debug 
# set -xv 

# number of colors supported 
__colors=$(tput colors 2> /dev/null) 

# foreground colors 
__black="$(tput setaf 0)" 
__red="$(tput setaf 1)" 
__green="$(tput setaf 2)" 
__yellow="$(tput setaf 3)" 
__blue="$(tput setaf 4)" 
__magenta="$(tput setaf 5)" 
__cyan="$(tput setaf 6)" 
__white="$(tput setaf 7)" 

# background colors 
__bg_black="$(tput setab 0)" 
__bg_red="$(tput setab 1)" 
__bg_green="$(tput setab 2)" 
__bg_yellow="$(tput setab 3)" 
__bg_blue="$(tput setab 4)" 
__bg_magenta="$(tput setab 5)" 
__bg_cyan="$(tput setab 6)" 
__bg_white="$(tput setab 7)" 

# style 
__reset="$(tput sgr0)" 
__bold="$(tput bold)" 
__underline="$(tput smul)" 

function has_colors() { 
    COLOR=${COLOR:-auto} 
    if [[ $COLOR = 'never' ]]; then 
    return 1 
    elif [[ $COLOR = 'always' ]]; then 
    return 0 
    else 
    [[ -t 1 ]] && [[ -n $__colors ]] && [[ $__colors -ge 8 ]] 
    fi 
} 

function __format() { 
    local format="$1" 
    local next="${2:-}" # next formatting function e.g. underline 
    if has_colors; then 
    echo -en "$format" 
    if [[ -n $next ]]; then 
     shift 2 
     tee | "$next" "[email protected]" 
    else 
     tee 
     echo -en "$__reset" 
    fi 
    else 
    tee #print output 
    fi 
} 

function black() { __format "$__black" "[email protected]"; } 
function red() { __format "$__red" "[email protected]"; } 
function green() { __format "$__green" "[email protected]";} 
function yellow() { __format "$__yellow" "[email protected]"; } 
function blue() { __format "$__blue" "[email protected]"; } 
function magenta() { __format "$__magenta" "[email protected]";} 
function cyan() { __format "$__cyan" "[email protected]";} 
function white() { __format "$__white" "[email protected]";} 

function bg_black() { __format "$__bg_black" "[email protected]"; } 
function bg_red() { __format "$__bg_red" "[email protected]"; } 
function bg_green() { __format "$__bg_green" "[email protected]";} 
function bg_yellow() { __format "$__bg_yellow" "[email protected]"; } 
function bg_blue() { __format "$__bg_blue" "[email protected]"; } 
function bg_magenta() { __format "$__bg_magenta" "[email protected]";} 
function bg_cyan() { __format "$__bg_cyan" "[email protected]";} 
function bg_white() { __format "$__bg_white" "[email protected]";} 

function bold() { __format "$__bold" "[email protected]";} 
function underline() { __format "$__underline" "[email protected]"; } 
+1

判斷管道是發送到管道還是被重定向的最好方法是檢查命令。如果stdout是tty(帶'test -t')並設置全局變量,請在啓動時檢查主shell。在每個函數中,檢查該變量。在腳本中,如果將管道重定向到文件,請不要調用彩色化函數!個人意見:不要打擾任何這一點。彩色效果看起來不錯,但是這種外殼太脆弱了,最終你會在凌晨3點看到一個沒有足夠咖啡的日誌文件,並希望它不會雜亂無章! –

+0

@WilliamPursell我寫作是一個可重用的庫,我想我會在未來某個時候將東西重定向到一個文件。我想如果我一旦破解它,這對我來說會非常有幫助。現在真的只是爲了個人使用。如果它證明是有用的,並且通過適當的測試,我認爲它會省下很多麻煩。或不 ?我更新了我的答案,我想我找到了一個很好的簡單解決方案。我知道ssh是不同的故事,將會有一個劇本來看看它是如何通過SSH或套接字工作的。有什麼想法嗎 ? – Bren

+1

你的解決方案很好(但它確實產生了額外的io,並且失敗了多行輸出;可能更乾淨,只做'紅色;下劃線;回顯一些文本;默認值'),但不可避免的是這種事情變得比它的價值更大。代碼的簡單性最終超過了彩色輸出的好處。最終「出乎意料地比預期的更早發生! –