使用 printf 將文字置中

使用 printf 將文字置中
printf "%*s\n" $(((${#fname}+$COLUMNS)/2)) "$fname"

我收到此錯誤:

line 9: (7+)/2: syntax error: operand expected (error token is ")/2")

這在終端機中有效,但在我的腳本中無效。你有什麼想法?

答案1

並非所有 shell 都將$COLUMNS變數設定為終端的寬度。

bash5.0 之前的版本僅在互動時設定它,而不是在腳本中設定。但是,從版本 4.3 開始,您仍然可以在非互動式 shell 中使用shopt -s checkwinsize.

然而,無論哪種情況,都有一個轉折點:在非互動式 shell 中啟用該選項(自 5.0 起預設啟用),直到子進程等待並退出後才會設定$COLUMNS/ (來源中提到的條目)$LINESNEWS前台作業退出後,這有點誤導,因為預設非互動式 shell 中沒有作業控制)。因此,在使用這些變數之前,您需要確保外部命令或子 shell 已同步執行:

#! /bin/bash -
shopt -s checkwinsize # for versions 4.3 and 4.4
(:) # start a synchronous subshell that runs the null command
echo "$COLUMNS $LINE"

另請注意,只有當 stderr 進入終端時才會發生這種情況(如果沒有,則保持未設定狀態),因此當無法確定螢幕寬度時$COLUMNS,您可能需要使用更${COLUMNS:-80}明智的預設值。bash

或者,您可以切換到即使在非交互時也zsh始終設置,$COLUMNS只要它在終端中運行($COLUMNS否則預設為 80),或者在任何類似 Bourne 的 shell 中使用iffor${COLUMNS:=$(tput cols)}設置的輸出來$COLUMNS$COLUMNStput cols

如果tput cols在您的系統上不起作用,您可以嘗試</dev/tty stty size | awk '{print $2}',或者zsh -c 'print $COLUMNS'

但請注意,一旦$COLUMNS以這種方式設置,無論何時調整終端大小,它都不會更新,因此您可能需要使用$(tput cols)always 來代替,以便每次在腳本中列印居中文字時都會查詢終端大小。

還要注意的是printf '%*s'zsh在和之外的 shell 中將fish文字填入給定數量位元組不是人物,因此該方法只能用於填充包含單字節、單寬度字元的文本,這些字元在使用 UTF-8 的語言環境中僅限於 US-ASCII 字元(所有可能字元的 0.011%)。

如果使用zsh而不是bash,您可以使用其left 和right 填充參數擴展標誌來代替(甚至可以使用該標誌處理零寬度或雙寬度字元m):

print -r -- ${(ml[COLUMNS/2]r[COLUMNS-COLUMNS/2])fname}

請注意,它會向左和向右填充(即螢幕的右邊緣)。您可以使用以下命令刪除右側填充(以及所有尾隨空白):

set -o extendedglob
print -r -- ${${(ml[COLUMNS/2]r[COLUMNS-COLUMNS/2])fname}%%[[:space:]]#}

包含著色/粗體/突出...轉義序列的居中文字會更加複雜。最簡單的方法可能是在獲取字串的寬度之前刪除它們。例如,與zsh、使用那種方法確定字串寬度(並處理 0 寬度或雙寬度字元)。

varwidth() (( ${(P)#1} * 3 - ${#${(ml[${(P)#1} * 2])${(P)1}}} ))
functions -Ms varwidth

varwidth_without_formatting() {
  set -o localoptions -o extendedglob
  local without_formatting=${(P)1//$'\e'\[[0-9;]#m}
  (( varwidth(without_formatting) ))
}
functions -Ms varwidth_without_formatting

center() {
  local text
  for text do
    print -r -- ${(l[(COLUMNS-varwidth_without_formatting(text))/2])}$text
  done
}

center $'\e[31mred\e[1;39mbold\e[m' \
       ${(%):-%F{green}Blah%F{yellow}blah%F{magenta}blah%f}

1 儘管在大多數系統上,您可以安裝 SIGWINCH 訊號的處理程序,如 @zevzek 在註釋中所示,這在最常見的情況下會有所幫助。

答案2

您可以嘗試從外部來源取得值,而不是變數 COLUMNS:

tput cols 

stty size | cut '-d ' -f1

答案3

請嘗試以下操作:

read WindowHeight WindowWidth<<<$(stty size)
printf "%$(((${#fname}+${WindowWidth})/2))s" "$fname"

COLUMNS 不會在腳本中自動設置,因此最好的選擇是使用 stty 取得目前視窗大小。這將在多個 shell 中工作(包括 bash、ksh、zsh)

相關內容