使用 printf 将文本居中

Dar*_*ner 1 bash printf text-formatting

printf "%*s\n" $(((${#fname}+$COLUMNS)/2)) "$fname"
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

line 9: (7+)/2: syntax error: operand expected (error token is ")/2")
Run Code Online (Sandbox Code Playgroud)

这在终端中有效,但在我的脚本中无效。你有什么想法?

Sté*_*las 5

并非所有 shell 都将$COLUMNS变量设置为终端的宽度。

\n

bash5.0 之前的版本仅在交互时设置它,而不是在脚本中设置。但是,从版本 4.3 开始,您仍然可以在非交互式 shell 中使用shopt -s checkwinsize.

\n

然而,无论哪种情况,都有一个转折:在非交互式 shell 中启用该选项(自 5.0 起默认启用),直到子进程等待并退出后才$COLUMNS设置/ (源中的条目在前台作业退出$LINESNEWS,这有点误导,因为在非交互式 shell 中默认没有作业控制)。因此,在使用这些变量之前,您需要确保外部命令或子 shell 已同步运行:

\n
#! /bin/bash -\nshopt -s checkwinsize # for versions 4.3 and 4.4\n(:) # start a synchronous subshell that runs the null command\necho "$COLUMNS $LINE"\n
Run Code Online (Sandbox Code Playgroud)\n

另请注意,只有当 stderr 进入终端时才会发生这种情况(如果没有,则保持未设置状态),因此当无法确定屏幕宽度时,$COLUMNS您可能需要使用${COLUMNS:-80}更明智的默认值。bash

\n

或者,您可以切换到即使在非交互时zsh也始终设置的值$COLUMNS,只要它在终端中运行($COLUMNS否则默认为 80),或者在任何类似 Bourne 的 shell${COLUMNS:=$(tput cols)}中使用$COLUMNSfor$COLUMNS代替从tput cols如果之前未设置或为空,则输出。

\n

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

\n

但请注意,一旦$COLUMNS以这种方式设置,每当调整终端大小时,它都不会更新\xc2\xb9,因此您可能需要使用$(tput cols)always来代替,这样每次在您的窗口中打印居中文本时都会查询终端大小。脚本。

\n

另请注意,在printf \'%*s\'之外的 shell 中,将文本填充到给定数量的字节而不是字符zshfish,因此该方法只能用于填充包含单字节、单宽度字符的文本,而在使用 UTF-8 的语言环境中,这些字符仅限于 US-ASCII个(所有可能字符的 0.011%)。

\n

如果使用zsh而不是bash,您可以使用其left 和right 填充参数扩展标志来代替(甚至可以使用该标志处理零宽度或双宽度字符m):

\n
print -r -- ${(ml[COLUMNS/2]r[COLUMNS-COLUMNS/2])fname}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,它会向左和向右填充(即屏幕的右边缘)。您可以使用以下命令删除右侧填充(以及所有尾随空格):

\n
set -o extendedglob\nprint -r -- ${${(ml[COLUMNS/2]r[COLUMNS-COLUMNS/2])fname}%%[[:space:]]#}\n
Run Code Online (Sandbox Code Playgroud)\n

包含着色/粗体/突出...转义序列的居中文本会更加复杂。最简单的方法可能是在获取字符串的宽度之前删除它们。例如,使用zsh,使用该方法来确定字符串宽度(并处理 0 宽度或双宽度字符)。

\n
varwidth() (( ${(P)#1} * 3 - ${#${(ml[${(P)#1} * 2])${(P)1}}} ))\nfunctions -Ms varwidth\n\nvarwidth_without_formatting() {\n  set -o localoptions -o extendedglob\n  local without_formatting=${(P)1//$\'\\e\'\\[[0-9;]#m}\n  (( varwidth(without_formatting) ))\n}\nfunctions -Ms varwidth_without_formatting\n\ncenter() {\n  local text\n  for text do\n    print -r -- ${(l[(COLUMNS-varwidth_without_formatting(text))/2])}$text\n  done\n}\n\ncenter $\'\\e[31mred\\e[1;39mbold\\e[m\' \\\n       ${(%):-%F{green}Blah%F{yellow}blah%F{magenta}blah%f}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

\xc2\xb9 尽管在大多数系统上,您可以安装 SIGWINCH 信号的处理程序,如 @zevzek 在注释中所示,这在最常见的情况下会有所帮助。

\n