![使用 printf 将文本居中](https://linux22.com/image/197425/%E4%BD%BF%E7%94%A8%20printf%20%E5%B0%86%E6%96%87%E6%9C%AC%E5%B1%85%E4%B8%AD.png)
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 中使用if的输出来${COLUMNS:=$(tput cols)}
设置$COLUMNS
for它之前未设置或为空。$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)