Shell

格式化輸出:下劃線

  • January 31, 2020

我編寫了以下函式,ksh它將它的第一個參數列印到螢幕上,並用適當數量的-字元為它加下劃線:

print_underlined () {
   word=$1 
   echo $word

   i=${#word}
   while [[ i -gt 0 ]]; do
       printf "-"
       (( i = $i - 1 ))
   done
   printf "\n"
}

例子:

$ print_underlined foobar
foobar
------
$

我想知道是否有一種更簡單、更優雅的方式來在螢幕上顯示帶下劃線的單詞。

對於我正在使用的記錄:

  • 索拉里斯 10
  • ksh88

您問題的核心是建構一個完全由下劃線組成的字元串,其長度與現有字元串的長度相同。在最近足夠多的 bash、ksh 或 zsh 版本中,您可以使用以下構造建構此字元串${VARIABLE//PATTERN/REPLACEMENT}underlines=${word//?/_}。但是這個結構在 ksh88 中不存在。

在任何 shell 中,您都可以使用tr。POSIX 兼容的實現tr讓您可以編寫以下程式碼:

underlines=$(printf %s "$word" | tr -c '_' '[_*]')

我認為 Solaris 10 預設具有 POSIX 兼容tr,但可能有一個歷史實現(與早期的 Solaris 版本兼容)。的歷史實現tr可能不理解[x*]語法,但他們傾向於接受以下語法(POSIX 不保證),意思是“用 替換所有不是換行符的內容_”:

underlines=$(echo "$word" | tr -c '\010' '_')
underlines=${underlines%_}

這是一個有點瘋狂的方法,它不使用任何循環或外部程序,並且應該在任何 Bourne shell 中工作(至少自從set -f引入以來——儘管在空目錄中執行會減輕缺少set -f. 不幸的是,它僅在字元串不包含任何空格時才有效。

set -f          # turn off globbing
IFS=$word       # split at any character in $word
set a $word     # split $word into one word between each character, i.e. empty words
shift           # remove the leading a (needed in case $word starts with -)
IFS=_
underlines=$*   # join the empty words, separated with the new value of $IFS

一個更複雜的變體處理空白,但前提是沒有任何連續的空白序列。我不認為你可以用這個技巧走得更遠,因為其中的空白字元序列IFS總是折疊的。

set -f
unset IFS; set a $0    # split at whitespace
IFS=$*; set $*         # split into empty words
IFS=_; underlines=$*   # collect the empty

引用自:https://unix.stackexchange.com/questions/38630