【问题标题】:Keep text in place regardless output bash printf无论输出 bash printf 都保持文本到位
【发布时间】:2020-01-22 14:34:24
【问题描述】:

当数字变大时会发生这种情况……刚开始就是这个烂摊子。 文本被更大的输出推来推去......我该如何控制这个混乱?

       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 ?? ??

应该是这样的:

       Accounts......: 5      Mail..........: 7
       Banned........: 0      Pets..........: 1
       Online........: 0      Tickets.......: 0
       Guilds........: 1      Corpses.......: 0      PvP.......: 0
       Members.......: 1      Characters....: 10     Gifts.....: 4

现在这个烂摊子是这样的:


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

在另一台服务器上有相同的输出,但因为它们更小,所以看起来不错:

           Accounts......: 4      Mail..........: 0
           Banned........: 0      Pets..........: 0
           Online........: 0      Tickets.......: 0
           Guilds........: 0      Corpses.......: 0      PvP.......: 0
           Members.......: 0      Characters....: 2      Gifts.....: 0

编辑此行以使其工作? 这是正确的起点吗?

cm_char="\033[0mCharacters\e[0;32m....:\033[0m $ch_count\e[31m"

杀了我。

【问题讨论】:

  • 您应该格式化您的数字,以便它们使用相同数量的空间。未显示获取输出所涉及的代码,因此无法提供更多帮助。只是一个指针:看看printf
  • 只需检查每个变量的长度并相应调整间距/$line 变量
  • 刚刚用 printf 更新了这些行,它从哪里得到它,其余的看起来一样。
  • " / $line 变量相应地" 但它们确实变大了...每次都编辑?
  • 确定最大数字是多少;这为您提供了该部分输出的最大宽度;修改您的输出命令以考虑“额外”宽度(例如,将 aprintf 格式从“%1s”调整为“%3s”以从 1 位数字变为 3 位数字)

标签: linux bash shell printf


【解决方案1】:

创建 2 个函数来格式化字段并使用它们:

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

编辑:添加颜色。

您不想让您的代码充满颜色的转义码。这取决于您希望如何构建颜色代码的完整上下文,我为问题的有限上下文提供了一个示例。它应该让您了解如何为自己制作这样的东西。

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

【讨论】:

  • 谢谢沃尔特 A !如此简单,我现在有空间玩了。
  • 如何添加颜色以及在哪里添加?数字和点。
  • 我可以像上次一样用颜色制作新的 $。 (这么多行)
  • @Antarctica 颜色已添加。
【解决方案2】:

您可能已经知道有一些特殊的系统序列 控制输出到终端。例如,这会将文本变为红色 '\e[31m' 这将在特定列\行'\e[${LINE};${COLUMN}H'中打印文本。 所以我们将使用它。首先,我将使用“名称值”对创建这个“数据”数组 模拟你的情况。

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"
)

我在处理文本输出时使用这个table,所以让我们用它来

#--------------------------------------------------------------------+
#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[*]}"; } #|
#--------------------------------------------------------------------+

所有基本颜色都设置为 vars,以便轻松插入文本和一些 像 XY 这样有用的功能,我会用它来在 serrtain 位置打印文本。

让我们设置一些变量

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

现在我们可以遍历数据并打印 3 列 4 行的文本

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)); }
}

最终的脚本会是这样的

    #!/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

输出会是这样的

【讨论】:

  • 我得到 XY: command not found on another linux with Ubuntu server。它适用于 MacBook 上的终端
  • @Antarctica,很高兴为您提供帮助)XY 这不是命令,而是我创建的函数。它来自“颜色表”。这是XY () { printf "\e[${2};${1}H${3}"; }
猜你喜欢
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多