问题
This happens when numbers gets bigger...Just started with this mess. Text being pushed around by bigger outputs...how do I contain this mess?
Accounts......: 5 Mail..........: 7
Banned........: 0 Pets..........: 1
Online........: 0 Tickets.......: 0
Guilds........: 1 Corpses.......: 0 PvP.......: 0
Members.......: 1 Characters....: 10 Gifts.....: 4 <-----HOWTO Reserve/Preserve spaces ?? ??
Should look like this:
Accounts......: 5 Mail..........: 7
Banned........: 0 Pets..........: 1
Online........: 0 Tickets.......: 0
Guilds........: 1 Corpses.......: 0 PvP.......: 0
Members.......: 1 Characters....: 10 Gifts.....: 4
Now this mess looks like this:
ch_count=$(mysql --defaults-extra-file="$sql_mycnf" -N --execute="SELECT count(*) FROM $db_characters.characters;"); &> /dev/null
cm_char="\033[0mCharacters\e[0;32m....:\033[0m $ch_count\e[31m"
line=" "
$cm_acco$line$cm_mail
$cm_bann$line$cm_pets
$cm_onli$line$cm_tick
$cm_guil$line$cm_corp$line$cm_pvps
$cm_memb$line$cm_char$line$cm_gifts
On another server there is same outputs but because they are smaller it looks fine:
Accounts......: 4 Mail..........: 0
Banned........: 0 Pets..........: 0
Online........: 0 Tickets.......: 0
Guilds........: 0 Corpses.......: 0 PvP.......: 0
Members.......: 0 Characters....: 2 Gifts.....: 0
Edit this line to make it work? Is this correct place to begin?
cm_char="\033[0mCharacters\e[0;32m....:\033[0m $ch_count\e[31m"
Kill me.
回答1:
Make 2 functions that will format the fields and use them:
dot_field() {
# todo Change implementation when field can be 2 words with a space in between
printf "%-14.14s:" "$1" | tr ' ' '.'
}
space_number() {
printf "%-7.7s" "$1"
}
printline() {
# Todo: add logic when only 4 parameters are given
echo " $(dot_field $1) $(space_number $2)$(dot_field $3) $(space_number $4)$(dot_field $5) $(space_number $6)"
}
printline "Guilds" 1 "Corpses" 0 "PvP" 0
printline "Members" 1 "Characters" 10 "Gifts" 4
printline "LongFieldName" 1 "High" 999999 "X" 2
EDIT: Adding colors.
You don't want to have your code full of escape codes for the colors. It depends on the full context how you would like to structure your color codes, I give an example for the limited context of the question. It should give you an idea how you can make something like this for yourself.
init_colors() {
reset=$(tput sgr0)
bold=$(tput bold)
black=$(tput setaf 0)
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
blue=$(tput setaf 4)
magenta=$(tput setaf 5)
cyan=$(tput setaf 6)
white=$(tput setaf 7)
user_color=$bold
}
# colorstring reads from stdin and uses parameter 1 as an escape sequence
# with more parameters the first is used as a color, the other as the string to be modified
# It will set colors until the last space sequence
colorstring() {
case $# in
0) # invalid
echo "colorstring called without parameters"
;;
1)
sed -r "s/^.*[^ ]/$1&${reset}/"
;;
*)
color="$1"
shift
sed -r "s/^.*[^ ]/${color}&${reset}/" <<< "$@"
;;
esac
}
dot_field() {
# todo Change implementation when field can be 2 words with a space in between
printf "%-14.14s" "$1" | colorstring ${cyan} | tr ' ' '.'
# The : must be printed in a second statement when you don't want cyan dots.
printf ':'
}
space_number() {
printf "%-7.7s" "$1" | colorstring ${red}
}
printline() {
echo " $(dot_field $1) $(space_number $2)$(dot_field $3) $(space_number $4)$(dot_field $5) $(space_number $6)"
}
# init the color variables
init_colors
# Next echo not needed, just testing the new colorstring function
echo "$(colorstring ${blue} blue string) $(colorstring ${red} red car) $(colorstring ${white} white snow) $(colorstring ${yellow} yellow marker) $(colorstring ${cyan} cyan) "
printline "Guilds" 1 "Corpses" 0 "PvP" 0
printline "Members" 1 "Characters" 10 "Gifts" 4
printline "LongFieldName" 1 "High" 999999 "X" 2
回答2:
As you may alredy know there are some spesial system sequinces that controll output to terminal. This for example will turn text red '\e[31m' and this will print text in certain column\line '\e[${LINE};${COLUMN}H'. So we will use that. First i will create this 'data' array with "name value" pairs to simulate your case.
data=(
"Accounts 5"
"Banned 10"
"Online 40"
"Guilds 4"
"Members 1"
"Mail 71"
"Pets 43"
"Tickets 0"
"Corpses 101"
"Characters 10"
"PvP 0"
"Gifts 4"
)
I'm using this table when working with text output so lets used it to
#--------------------------------------------------------------------+
#Color picker, usage: printf ${BLD}${CUR}${RED}${BBLU}"Hello!)"${DEF}|
#-------------------------+--------------------------------+---------+
# Text color | Background color | |
#-----------+-------------+--------------+-----------------+ |
# Base color|Lighter shade| Base color | Lighter shade | |
#-----------+-------------+--------------+-----------------+ |
BLK='\e[30m'; blk='\e[90m'; BBLK='\e[40m'; bblk='\e[100m' #| Black |
RED='\e[31m'; red='\e[91m'; BRED='\e[41m'; bred='\e[101m' #| Red |
GRN='\e[32m'; grn='\e[92m'; BGRN='\e[42m'; bgrn='\e[102m' #| Green |
YLW='\e[33m'; ylw='\e[93m'; BYLW='\e[43m'; bylw='\e[103m' #| Yellow |
BLU='\e[34m'; blu='\e[94m'; BBLU='\e[44m'; bblu='\e[104m' #| Blue |
MGN='\e[35m'; mgn='\e[95m'; BMGN='\e[45m'; bmgn='\e[105m' #| Magenta |
CYN='\e[36m'; cyn='\e[96m'; BCYN='\e[46m'; bcyn='\e[106m' #| Cyan |
WHT='\e[37m'; wht='\e[97m'; BWHT='\e[47m'; bwht='\e[107m' #| White |
#----------------------------------------------------------+---------+
# Effects |
#--------------------------------------------------------------------+
DEF='\e[0m' #Default color and effects |
BLD='\e[1m' #Bold\brighter |
DIM='\e[2m' #Dim\darker |
CUR='\e[3m' #Italic font |
UND='\e[4m' #Underline |
INV='\e[7m' #Inverted |
COF='\e[?25l' #Cursor Off |
CON='\e[?25h' #Cursor On |
#--------------------------------------------------------------------+
# Text positioning, usage: XY 10 10 "Hello World!" |
XY () { printf "\e[${2};${1}H${3}"; } # |
#--------------------------------------------------------------------+
# Print line, usage: line - 10 | line -= 20 | line "Hello World!" 20 |
line () { printf -v LINE "%$2s"; printf -- "${LINE// /$1}"; } # |
# Create sequence like {0..X} |
cnt () { printf -v _N %$1s; _N=(${_N// / 1}); printf "${!_N[*]}"; } #|
#--------------------------------------------------------------------+
There are all basic colors set as vars to easily insert in text and some usefull functions like XY i'll use it to print text in serrtain position.
Lets set some vars
space_betwen=7 # space betwen columns
X=$space_betwen # starting X(column) position
Y=10 # starting Y(line) position
dot_string='...............: ' # dot string to simulate your output
dot_length=${#dot_string} # this will calculate the length of the dot string
Ok we are ready to go but first lets clear all text from terminal screen
clear
And now we can iterate through data and print text in 3 columns by 4 lines
for item in "${data[@]}"; {
((counter++)) # lets count items to know when start next column
read name value <<< $item # get naame and value from current item
XY $X $Y "$dot_string$RED$value$DEF" # print dot string and red value
XY $X $Y "$YLW$name$DEF" # name will be printed ower dots in yelow color
((Y++)) # go to next line by increasing Y value
# chek if we print 4 lines than set Y to start poosition and inc X to space_betwen+dot_length
((counter%4)) || { Y=10; ((X+=space_betwen+dot_length)); }
}
The final script will be like this
#!/bin/bash
data=(
"Accounts 5"
"Banned 10"
"Online 40"
"Guilds 4"
"Members 1"
"Mail 71"
"Pets 43"
"Tickets 0"
"Corpses 101"
"Characters 10"
"PvP 0"
"Gifts 4"
)
. ~/SCR/color # include color table
space_betwen=7 # space betwen columns
X=$space_betwen # starting X(column) position
Y=10 # starting Y(line) position
dot_string='...............: ' # dot string to simulate your output
dot_length=${#dot_string} # this will calculate the length of the dot string
clear
for item in "${data[@]}"; {
((counter++)) # lets count items to know when start next column
read name value <<< $item # get naame and value from current item
XY $X $Y "$dot_string$RED$value$DEF" # print dot string and red value
XY $X $Y "$YLW$name$DEF" # name will be printed ower dots in yelow color
((Y++)) # go to next line by increasing Y value
# chek if we print 4 lines than set Y to start poosition and inc X to space_betwen+dot_length
((counter%4)) || { Y=10; ((X+=space_betwen+dot_length)); }
}
XY 1 20 "$DEF" # one more time to move cursor down in the end
And the output will be like this
来源:https://stackoverflow.com/questions/59862020/keep-text-in-place-regardless-output-bash-printf