我创建了这个函数,它打印示例图像中所示的输出。但是,这个功能的实现似乎太复杂了。
有没有办法可以改进它或实施替代解决方案?
#!/bin/bash
function box_out() {
input_char=$(echo "$@" | wc -c)
line=$(for i in `seq 0 $input_char`; do printf "-"; done)
# tput This should be the best option. what tput does is it will
# read the terminal info and render the correctly escaped ANSI code
# for you.
# Code like \033[31m will break the readline library in some of the
# terminals.
tput bold
line="$(tput setaf 3)${line}"
space=${line//-/ }
echo " ${line}"
printf '|' ; echo -n "$space" ; printf "%s\n" '|';
printf '| ' ;tput setaf 4; echo -n "$@"; tput setaf 3 ; printf "%s\n" ' |';
printf '|' ; echo -n "$space" ; printf "%s\n" '|';
echo " ${line}"
tput sgr 0
}
box_out $@
答案1
由于您的 shebang 和语法表明 unportable bash
,我更喜欢这种方式:
function box_out()
{
local s="$*"
tput setaf 3
echo " -${s//?/-}-
| ${s//?/ } |
| $(tput setaf 4)$s$(tput setaf 3) |
| ${s//?/ } |
-${s//?/-}-"
tput sgr 0
}
当然,如果你愿意的话,你可以对其进行优化。
更新根据评论中的要求,也可以处理多行文本。
function box_out()
{
local s=("$@") b w
for l in "${s[@]}"; do
((w<${#l})) && { b="$l"; w="${#l}"; }
done
tput setaf 3
echo " -${b//?/-}-
| ${b//?/ } |"
for l in "${s[@]}"; do
printf '| %s%*s%s |\n' "$(tput setaf 4)" "-$w" "$l" "$(tput setaf 3)"
done
echo "| ${b//?/ } |
-${b//?/-}-"
tput sgr 0
}
使用多个参数调用它,例如box_out 'first line' 'more line' 'even more line'
.
答案2
所以,我的解决方案不是相当和你的一样,但严格来说它在文本周围打印一个框,并且实现更简单,所以我想我会分享。
banner() {
msg="# $* #"
edge=$(echo "$msg" | sed 's/./#/g')
echo "$edge"
echo "$msg"
echo "$edge"
}
它正在发挥作用:
$ banner "hi"
######
# hi #
######
$ banner "hi there"
############
# hi there #
############
只有纯文本,没有花哨的 ansi 颜色或任何东西。
答案3
盒子!
$ echo 'Love Unix & Linux' | boxes -d stone -p a2v1
+---------------------+
| |
| Love Unix & Linux |
| |
+---------------------+
自从boxes
需要将文本作为文件发送给它,因此我建议使用上面示例中的语法,其中文本boxes
通过管道传输到echo
.
“为什么boxes
?”
使用它很容易。只需告诉它您想要使用什么边框设计以及您希望它如何显示,然后就完成了。
当然,如果你想发挥创意,也可以自己设计。这真的很容易而且很有趣。使用的唯一缺点boxes
是我还没有弄清楚如何将使用生成的框居中boxes
使中心与屏幕对齐,尽管有一个 bash hack
“那颜色呢?”
最初的问题演示了颜色代码的使用。所以似乎只有展示如何才能正确boxes
处理这个问题才是正确的。
虽然tput
很流行,但我认为自己是一个老派的 Bash 人,并且仍然喜欢使用转义命令。我确信 StackExchange 中有一些人会反对它,但每个人都有自己的看法。无论如何,我愿意抛开我个人的偏好,包括另一个这样做的例子tput
。
当然,我认为第一步是设置内部文本的颜色。那么我们先这样做吧。
printf "$(tput setaf 4)Love Unix & Linux$(tput sgr 0)" | boxes -d stone -p a2v1
+---------------------------------+
| |
| Love Unix & Linux |
| |
+---------------------------------+
如果这是在终端中,Love Unix & Linux
将会是蓝色的......但是正如你所看到的,boxes
没有很好地处理这个问题。那么什么是没有错的呢?
printf "$(tput setaf 4)Love Unix & Linux$(tput sgr 0)" | boxes -d stone -p a2v1 | cat -A
+---------------------------------+$
| |$
| ^[[34mLove Unix & Linux^[(B^[[0m |$
| |$
+---------------------------------+$
cat -A
通过显示隐藏的角色来仔细检查boxes
假定框的长度包括文本长度和转义字符。
但应该注意的是,如果您使用类似的程序lolcat
外部的boxes
,输出看起来像这样
$ echo 'Love Unix & Linux' | boxes -d stone -p a2v1 | lolcat -f
+---------------------+
| |
| Love Unix & Linux |
| |
+---------------------+
但盒子和文字都是彩虹色的。
幸好我还没有制作自己的边框设计,其中包含颜色代码,因为我想边框设计也会遇到同样的问题。
居中文本、ASCII 艺术和方框!!!
另一个缺陷弄清楚了。boxes
是,如果您知道如何使用 Bash 将文本居中到终端的中心,boxes
仍然会将框与屏幕左侧对齐。
当您想要将不在框中的文本居中时,您可以简单地使用
center(){
COLS=$(tput cols) # use the current width of the terminal.
printf "%*s\n" "$(((${#1}+${COLS})/2))" "$1"
}
并用它来居中一行文本。
center 'Love Unix & Linux'
对于使用多行且必须固定到位的 ascii-art,有此选项。
# Rather than removing text, even things out by padding lines with spaces
draw_banner(){
local banner="$1"
# Banner Width
BW=$(cat $banner | awk '{print length}' | sort -nr | head -1)
while IFS= read -r line; do
line=$(echo "${line}" | sed -n -e 's/^ / /g;p')
line=$(printf "%-${BW}s" "${line}")
center "${line}" # our center function from earlier.
done < "$banner"
}
draw_banner "path/to/your_ascii_art_logo.txt"
但如果您喜欢使用诸如 之类的功能figlet
,则无需使用这些功能,因为该-c
选项提供了居中选项。
$figfontdir="path/to/figlet/fonts"
$figfont="Alligator"
text_banner(){
COLS=$(tput cols) # use the width of the terminal!
figlet -d "$figfontdir" -f "$figfont" -k -w $COLS -c "$1"
}
text_banner 'Love Unix & Linux'
对于boxes
,我们做了类似的事情,draw_banner()
但我们需要通过管道传输数据!
# Center a box created with `boxes
# It's like draw_banner, but `<<<` reads a string of data rather than a file.
$boxfile="/path/to/your_box_designs.box" # or ".txt". I like ".box".
$boxdesgin="stone"
center_box(){
local data="$(</dev/stdin)" # Read from standard input
# Banner Width
BW=$(cat <<< ${data} | awk '{print length}' | sort -nr | head -1)
while IFS= read -r line; do
line=$(echo "${line}" | sed -n -e 's/^ / /g;p')
line=$(printf "%-${BW}s" "${line}")
center "${line}" # our center command from earlier.
done <<< "${data}"
}
(
# A bunch of stuff to center!
) | boxes -f $boxfile -d $boxdesign -a hcvcjc | center_box
显着的问题
解决这两个问题( UTF/ANSI 字符问题)不仅可以为boxes
将文本封装在 ASCII 框中提供更好的解决方案,而且可以提供一种创造性的替代方案,而不是手动编码框。
答案4
我最近刚用过manatwork 的多行框答案在我的项目中,我将其修改为可以创建横幅 - 文本居中,没有边缘,甚至采用 BASH 颜色参数(可选的第二个参数可以更改文本的颜色)。我为我想在项目中使用的每种 bash 颜色创建了标签(即 RED='\e[31m')
# Multi line banners are generated like `banner ${COLOR} ${OPTIONAL_SECONDCOLOR} "first line" "second line" "third line"`
function banner() {
local s=("${@:3}") b w
local second_color=$2
if [[ ! "$second_color" =~ "\e[".* ]]; then #If the second color isn't declared, then make the function use only the first color declared
local s=("${@:2}") b w
local second_color=$1
fi
for l in "${s[@]}"; do
((w<${#l})) && { b=" $l "; w="${#l}"; }
done
echo -ne $1
echo "-${b//?/-}-"
for l in "${s[@]}"; do
printf ' %s%*s%s \n' "$(echo -ne $second_color)" "-$w" "$l" "$(echo -ne $1)"
done
echo -e "-${b//?/-}-${NC}"
}
用法示例:
banner ${LIGHT_PURPLE} "test here something line 1. SUPER LONG AND IT REALLY NEEDS TO BE LONG" "super duper long line 2" # Single Color option
banner ${LIGHT_PURPLE} ${RED} " This should be red now test here something line 1. SUPER LONG AND IT REALLY NEEDS TO BE LONG" "super duper long line 2" #Two Color Option