使用 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 中使用if的输出来${COLUMNS:=$(tput cols)}设置$COLUMNSfor它之前未设置或为空。$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)

相关内容