我是新手。我正在寻找用于居中和对齐文本的 bash 脚本。我的脚本仅适用于一行文本。您如何改进它?
#!/bin/bash
COLS=$(tput cols)
while true; do
clear
echo -n "Type text "
read text
echo
echo "Menu"
echo "1) Right justify "
echo "2) Center "
echo "3) Exit "
echo
echo -n "Choose [1-3]: "
read opt
echo
case $opt in
1) printf "%*s\n" $COLS "$text"
break
;;
2) printf "%*s\n" $[$COLS/2] "$text"
break
;;
3) break
;;
*)
echo "Error. Press [1-3]"
break
;;
esac
done
答案1
正如您所发现的,$COLUMNS
仅在交互式 shell 中有用-i
,因此我们使用columns="$(tput cols)"
。
我唯一遇到的问题是下面这一行。它没有将文本居中。
printf "%*s\n" $[$COLS/2] "$text"
扩展您的工作,这里有一个显示居中文本的函数(来自文件)。要在脚本中调用它,请使用display_center "file.txt"
display_center(){
columns="$(tput cols)"
while IFS= read -r line; do
printf "%*s\n" $(( (${#line} + columns) / 2)) "$line"
done < "$1"
}
请注意使用${#line}
(类似于wc -m
)来计算行中的字符数。只要您只需要显示纯文本而不显示颜色/格式,那么这应该可以正常工作。
这是一个使用与 printf 相同的实现来显示右对齐文本(来自文件)的函数。
display_right(){
columns="$(tput cols)"
while IFS= read -r line; do
printf "%*s\n" $columns "$line"
done < "$1"
}
您也可以使用 tput 和 echo 做类似的事情,但下面的示例不是那么强大(即,长字符串将会失败)。
row=0
col=$(( ($(tput cols) - ${#text}) / 2))
tput clear
tput cup $row $col
echo "$text"
另外,您可能要考虑使用dialog
或select
来生成菜单。这将使您的脚本更加简洁。
http://bash.cyberciti.biz/guide/Select_loop
https://serverfault.com/questions/144939/multi-select-menu-in-bash-script
答案2
#!/usr/bin/awk -f
{
z = 92 - length
y = int(z / 2)
x = z - y
printf "%*s%s%*s\n", x, "", $0, y, ""
}
输入
你好世界 阿尔法 布拉沃 查理 德尔塔
输出
你好世界 阿尔法 布拉沃 查理 德尔塔
答案3
我已经玩脚本一段时间了。我是一名木匠和机械师,所以请耐心听我说,哈哈。我知道这是一个老问题,但我最近在寻找类似的东西来美化我一直在研究的过于复杂的 Arch 安装脚本,但从未找到符合我需求的答案。所以我写了一个(可能有点黑客)函数,它提供了一些选项来简化我正在寻找的格式。我想如果有人感兴趣的话我会分享一下。这一切都是在 zsh 中完成的。
# Formatting using printf
#
# _L == total length for 'L' and 'R' options
# tl == total length for 'C' option
# _c == center for 'C' option ( tl / 2 )
# fill == filler character or space by default
#
# Default lengths declared at top of function
#
# usage $) f_M [string] [L,R,C] [character count]
# -S option:
# $) f_M -S [character] [total length (- for default 'space')]
# -3rd var ($3) is needed for filler character ($2) or
# else ($2) is total length
#
#
f_M () {
tl=72
_c=36
_L=16
f_numread () {
printf $1 | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
}
f_C () {
local x=$(printf $1 | wc -c)
local y=$(expr $_c - $(expr $x / 2))
local z=$(expr $tl - $y)
local space=' '
printf "%${y}s%-${z}s\n" "$space" "$1"
}
case $1 in
-S)
fill=' '
if [[ -n $2 ]]; then
if [[ -n $3 ]]; then
fill="$2"
if [[ $3 =~ ^-?[0-9]+$ ]]; then
tl=$3
fi
else
if [[ $2 =~ ^-?[0-9]+$ ]]; then
tl=$2
fi
fi
fi
printf "${fill}%.0s" {1..$tl}
;;
*)
if [[ $3 =~ ^-?[0-9]+$ ]]; then
tl=$3
_L=$3
_c=$(expr $tl / 2)
fi
if [[ $1 =~ ^-?[0-9]+$ ]]; then
local x=$(f_numread $1)
case $2 in
L)
printf "%-${_L}s\n" "$x" ;;
R)
printf "%${_L}s\n" "$x" ;;
C)
f_C $x ;;
"")
printf '%s\n' $x
esac
else
case $2 in
L)
printf "%-${_L}s\n" "$1" ;;
R)
printf "%${_L}s\n" "$1" ;;
C)
f_C $1 ;;
"")
printf '%s\n' $1
esac
fi
;;
esac
}
以下是我使用它的一些示例...
# Default character length is 72
[user@arch]$ printf '%s\n' "<$(f_M -S)>"
< >
[user@arch]$ printf '%s\n' "<$(f_M -S = 50)>"
<==================================================>
# To change the 'fill' character(s), a 3rd argument is required
# So I set '-' to keep my default value
# There is probably a better way to do it but this fit my needs
[user@arch]$ printf '%s\n' "<$(f_M -S = -)>"
<========================================================================>
# Because of what I was trying to do and to get multiple uses out of
# one function, I use separate variables for 'C' than for 'L' and 'R'
[user@arch]$ printf '%s\n%s\n%s\n' "<$(f_M 'left' L 72)>" \
"<$(f_M 'center' C)>" "<$(f_M 'right' R 72)>"
<left >
< center >
< right>
# It will also take a string that is only numbers and make
# it more "human readable"
[user@arch]$ num=12345678
[user@arch]$ printf '%s\n' "<$(f_M ${num} C 50)>"
< 12,345,678 >
为了更具创造力,我可以添加另一个函数,该函数将使用数组自动创建一个漂亮的文本框……
#!/bin/zsh
f_fancy_box () {
local s=''
for s in ${text[@]}; do
case $s in
000) printf '%b\n' "<$(f_M -S = -)>" ;;
---) printf '%b\n' "| $(f_M -S - 70) |" ;;
*) printf '%b\n' "|$(f_M $s C)|" ;;
esac
done
}
text=(
"000"
" "
"It is hobbies like this"
"that keep me from ever"
"getting any sleep lol"
" "
"---"
" "
"But I think"
"it is worth it"
":P"
" "
"000"
)
f_fancy_box
exit
输出:
<========================================================================>
| |
| It is hobbies like this |
| that keep me from ever |
| getting any sleep lol |
| |
| ---------------------------------------------------------------------- |
| |
| But I think |
| it is worth it |
| :P |
| |
<========================================================================>
我希望有人觉得这有用!
编辑:将 f_fancy_box 中的 printf '%s' 更改为 '%b'。根据 printf 的手册页,为了允许字符转义,我认为这实际上是合适的命令。如果我错了,请纠正我...
答案4
A功能接收文本并将其水平居中,大批也可以用来输入文本。
它的工作原理如下,细绳传递给函数并保存在数组中,然后使用for 循环遍历数组,并在终端中心打印每一行。
function centerText() {
columns="$(tput cols)"
declare -a text=()
text+=($*)
for((i=0;i<${#text[@]};i++)); do
printf "%*s\n" $(( (${#text[i]} + columns) / 2)) "${text[i]}"
done
}
以下是一个例子:
function centerText() {
columns="$(tput cols)"
declare -a text=()
text+=($*)
for((i=0;i<${#text[@]};i++)); do
printf "%*s\n" $(( (${#text[i]} + columns) / 2)) "${text[i]}"
done
}
declare -a text=(
'First'
'Second'
'Third'
)
centerText ${text[@]}
sleep 5
输出:
First
Second
Third
PD:如果有表述错误的话,请见谅,我的母语不是英语。