printf "%*s\n" $(((${#fname}+$COLUMNS)/2)) "$fname"
我收到此錯誤:
line 9: (7+)/2: syntax error: operand expected (error token is ")/2")
這在終端機中有效,但在我的腳本中無效。你有什麼想法?
答案1
並非所有 shell 都將$COLUMNS
變數設定為終端的寬度。
bash
5.0 之前的版本僅在互動時設定它,而不是在腳本中設定。但是,從版本 4.3 開始,您仍然可以在非互動式 shell 中使用shopt -s checkwinsize
.
然而,無論哪種情況,都有一個轉折點:在非互動式 shell 中啟用該選項(自 5.0 起預設啟用),直到子進程等待並退出後才會設定$COLUMNS
/ (來源中提到的條目)$LINES
NEWS
前台作業退出後,這有點誤導,因為預設非互動式 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
$COLUMNS
tput 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
,您可以使用其l
eft 和r
ight 填充參數擴展標誌來代替(甚至可以使用該標誌處理零寬度或雙寬度字元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)