printf 中的填充字符

发布于 2024-10-06 21:12:20 字数 616 浏览 1 评论 0原文

我正在编写一个 bash shell 脚本来显示进程是否正在运行。

到目前为止,我得到了这个:

printf "%-50s %s\n" $PROC_NAME [UP]

代码给了我这个输出:

JBoss                                              [DOWN]

GlassFish                                          [UP]

verylongprocessname                                [UP]

我想用“-”或“*”填充两个字段之间的间隙,以使其更具可读性。如何在不影响字段对齐的情况下做到这一点?

我想要的输出是:

JBoss -------------------------------------------  [DOWN]

GlassFish ---------------------------------------  [UP]

verylongprocessname -----------------------------  [UP]

I am writing a bash shell script to display if a process is running or not.

So far, I got this:

printf "%-50s %s\n" $PROC_NAME [UP]

The code gives me this output:

JBoss                                              [DOWN]

GlassFish                                          [UP]

verylongprocessname                                [UP]

I want to pad the gap between the two fields with a '-' or '*' to make it more readable. How do I do that without disturbing the alignment of the fields?

The output I want is:

JBoss -------------------------------------------  [DOWN]

GlassFish ---------------------------------------  [UP]

verylongprocessname -----------------------------  [UP]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

末骤雨初歇 2024-10-13 21:12:20

纯 Bash,无外部实用程序

此演示提供了完整的理由,但如果您想要右侧参差不齐的行,则可以省略减去第二个字符串的长度。

pad=$(printf '%0.1s' "-"{1..60})
padlength=40
string2='bbbbbbb'
for string1 in a aa aaaa aaaaaaaa
do
     printf '%s' "$string1"
     printf '%*.*s' 0 $((padlength - ${#string1} - ${#string2} )) "$pad"
     printf '%s\n' "$string2"
     string2=${string2:1}
done

不幸的是,使用这种技术,填充字符串的长度必须被硬编码为比您认为需要的最长长度更长,但是 padlength 可以是一个变量,如图所示。但是,您可以用这三行替换第一行,以便能够使用变量来表示 pad 的长度:

padlimit=60
pad=$(printf '%*s' "$padlimit")
pad=${pad// /-}

因此 pad (padlimitpadlength) 可以基于取决于终端宽度 ($COLUMNS) 或根据最长数据字符串的长度计算。

输出:

a--------------------------------bbbbbbb
aa--------------------------------bbbbbb
aaaa-------------------------------bbbbb
aaaaaaaa----------------------------bbbb

不减去第二个字符串的长度:

a---------------------------------------bbbbbbb
aa--------------------------------------bbbbbb
aaaa------------------------------------bbbbb
aaaaaaaa--------------------------------bbbb

第一行可以是等效的(类似于 sprintf):

printf -v pad '%0.1s' "-"{1..60}

或者类似地对于更动态的技术:

printf -v pad '%*s' "$padlimit"

或者这个(允许多字符“省略号” " 无需修改格式字符串来容纳字符数 - 上例中的 .1)。它假定名称为 $_1$_2 等的变量未设置或为空。:

printf -v pad '%s' "<>"$_{1..60}  

如果您愿意,可以将所有内容打印在一行上:

printf '%s%*.*s%s\n' "$string1" 0 $((padlength - ${#string1} - ${#string2} )) "$pad" "$string2"

Pure Bash, no external utilities

This demonstration does full justification, but you can just omit subtracting the length of the second string if you want ragged-right lines.

pad=$(printf '%0.1s' "-"{1..60})
padlength=40
string2='bbbbbbb'
for string1 in a aa aaaa aaaaaaaa
do
     printf '%s' "$string1"
     printf '%*.*s' 0 $((padlength - ${#string1} - ${#string2} )) "$pad"
     printf '%s\n' "$string2"
     string2=${string2:1}
done

Unfortunately, with that technique, the length of the pad string has to be hardcoded to be longer than the longest one you think you'll need, but the padlength can be a variable as shown. However, you can replace the first line with these three to be able to use a variable for the length of the pad:

padlimit=60
pad=$(printf '%*s' "$padlimit")
pad=${pad// /-}

So the pad (padlimit and padlength) could be based on terminal width ($COLUMNS) or computed from the length of the longest data string.

Output:

a--------------------------------bbbbbbb
aa--------------------------------bbbbbb
aaaa-------------------------------bbbbb
aaaaaaaa----------------------------bbbb

Without subtracting the length of the second string:

a---------------------------------------bbbbbbb
aa--------------------------------------bbbbbb
aaaa------------------------------------bbbbb
aaaaaaaa--------------------------------bbbb

The first line could instead be the equivalent (similar to sprintf):

printf -v pad '%0.1s' "-"{1..60}

Or similarly for the more dynamic technique:

printf -v pad '%*s' "$padlimit"

Or this (which allows multi-character "ellipses" without having to modify the format string to accommodate the number of characters - .1 in the example above). It assumes that variables with names such as $_1, $_2, etc., are unset or empty.:

printf -v pad '%s' "<>"$_{1..60}  

You can do the printing all on one line if you prefer:

printf '%s%*.*s%s\n' "$string1" 0 $((padlength - ${#string1} - ${#string2} )) "$pad" "$string2"
酒中人 2024-10-13 21:12:20

纯粹的巴什。使用“PROC_NAME”值的长度作为固定字符串“line”的偏移量:

line='----------------------------------------'
PROC_NAME='abc'
printf "%s %s [UP]\n" $PROC_NAME "${line:${#PROC_NAME}}"
PROC_NAME='abcdef'
printf "%s %s [UP]\n" $PROC_NAME "${line:${#PROC_NAME}}"

这给出

abc ------------------------------------- [UP]
abcdef ---------------------------------- [UP]

Pure Bash. Use the length of the value of 'PROC_NAME' as offset for the fixed string 'line':

line='----------------------------------------'
PROC_NAME='abc'
printf "%s %s [UP]\n" $PROC_NAME "${line:${#PROC_NAME}}"
PROC_NAME='abcdef'
printf "%s %s [UP]\n" $PROC_NAME "${line:${#PROC_NAME}}"

This gives

abc ------------------------------------- [UP]
abcdef ---------------------------------- [UP]
夜光 2024-10-13 21:12:20

简单(但有效)的解决方案:

echo -e "---------------------------- [UP]\r$PROC_NAME "

Trivial (but working) solution:

echo -e "---------------------------- [UP]\r$PROC_NAME "
神仙妹妹 2024-10-13 21:12:20

我认为这是最简单的解决方案。纯 shell 内置函数,没有内联数学。它借鉴了以前的答案。

只是子字符串和 ${#...} 元变量。

A="[>---------------------<]";

# Strip excess padding from the right
#

B="A very long header"; echo "${A:0:-${#B}} $B"
B="shrt hdr"          ; echo "${A:0:-${#B}} $B"

生产

[>----- A very long header
[>--------------- shrt hdr


# Strip excess padding from the left
#

B="A very long header"; echo "${A:${#B}} $B"
B="shrt hdr"          ; echo "${A:${#B}} $B"

产品 生产产品

-----<] A very long header
---------------<] shrt hdr

I think this is the simplest solution. Pure shell builtins, no inline math. It borrows from previous answers.

Just substrings and the ${#...} meta-variable.

A="[>---------------------<]";

# Strip excess padding from the right
#

B="A very long header"; echo "${A:0:-${#B}} $B"
B="shrt hdr"          ; echo "${A:0:-${#B}} $B"

Produces

[>----- A very long header
[>--------------- shrt hdr


# Strip excess padding from the left
#

B="A very long header"; echo "${A:${#B}} $B"
B="shrt hdr"          ; echo "${A:${#B}} $B"

Produces

-----<] A very long header
---------------<] shrt hdr
对你再特殊 2024-10-13 21:12:20

简单但确实有效:

printf "%-50s%s\n" "$PROC_NAME~" "~[$STATUS]" | tr ' ~' '- '

使用示例:

while read PROC_NAME STATUS; do  
    printf "%-50s%s\n" "$PROC_NAME~" "~[$STATUS]" | tr ' ~' '- '
done << EOT 
JBoss DOWN
GlassFish UP
VeryLongProcessName UP
EOT

输出到标准输出:

JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]
VeryLongProcessName ------------------------------ [UP]

Simple but it does work:

printf "%-50s%s\n" "$PROC_NAME~" "~[$STATUS]" | tr ' ~' '- '

Example of usage:

while read PROC_NAME STATUS; do  
    printf "%-50s%s\n" "$PROC_NAME~" "~[$STATUS]" | tr ' ~' '- '
done << EOT 
JBoss DOWN
GlassFish UP
VeryLongProcessName UP
EOT

Output to stdout:

JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]
VeryLongProcessName ------------------------------ [UP]
初心 2024-10-13 21:12:20

使用 printf 无法填充除空格之外的任何内容。您可以使用 sed:

printf "%-50s@%s\n" $PROC_NAME [UP] | sed -e 's/ /-/g' -e 's/@/ /' -e 's/-/ /'

There's no way to pad with anything but spaces using printf. You can use sed:

printf "%-50s@%s\n" $PROC_NAME [UP] | sed -e 's/ /-/g' -e 's/@/ /' -e 's/-/ /'
一百个冬季 2024-10-13 21:12:20
echo -n "$PROC_NAME $(printf '\055%.0s' {1..40})" | head -c 40 ; echo -n " [UP]"

说明:

  • printf '\055%.0s' {1..40} - 创建 40 个破折号
    (破折号被解释为选项,因此请使用转义的 ascii 代码)
  • "$PROC_NAME ..." - 连接 $PROC_NAME 和破折号
  • | head -c 40 - 将字符串修剪为前 40 个字符
echo -n "$PROC_NAME $(printf '\055%.0s' {1..40})" | head -c 40 ; echo -n " [UP]"

Explanation:

  • printf '\055%.0s' {1..40} - Create 40 dashes
    (dash is interpreted as option so use escaped ascii code instead)
  • "$PROC_NAME ..." - Concatenate $PROC_NAME and dashes
  • | head -c 40 - Trim string to first 40 chars
画骨成沙 2024-10-13 21:12:20

这个更简单并且不执行外部命令。

$ PROC_NAME="JBoss"
$ PROC_STATUS="UP"
$ printf "%-.20s [%s]\n" "${PROC_NAME}................................" "$PROC_STATUS"

JBoss............... [UP]

This one is even simpler and execs no external commands.

$ PROC_NAME="JBoss"
$ PROC_STATUS="UP"
$ printf "%-.20s [%s]\n" "${PROC_NAME}................................" "$PROC_STATUS"

JBoss............... [UP]
邮友 2024-10-13 21:12:20

仅使用 echo

@Dennis Williamson 的 anwser 工作得很好,除了我试图使用 echo 来做到这一点。 Echo 允许输出具有特定颜色的字符。使用 printf 会删除该颜色并打印不可读的字符。这是仅 echo 的替代方案:

string1=abc
string2=123456
echo -en "$string1 "
for ((i=0; i< (25 - ${#string1}); i++)){ echo -n "-"; }
echo -e " $string2"

输出:

abc ---------------------- 123456

当然,您可以使用 @Dennis Williamson 提出的所有变体,无论您希望右侧部分左对齐还是右对齐(替换 25 - ${#string1} by 25 - ${#string1} - ${#string2} 等...

using echo only

The anwser of @Dennis Williamson is working just fine except I was trying to do this using echo. Echo allows to output charcacters with a certain color. Using printf would remove that coloring and print unreadable characters. Here's the echo-only alternative:

string1=abc
string2=123456
echo -en "$string1 "
for ((i=0; i< (25 - ${#string1}); i++)){ echo -n "-"; }
echo -e " $string2"

output:

abc ---------------------- 123456

of course you can use all the variations proposed by @Dennis Williamson whether you want the right part to be left- or right-aligned (replacing 25 - ${#string1} by 25 - ${#string1} - ${#string2} etc...

最好是你 2024-10-13 21:12:20

这是另一个:

$ { echo JBoss DOWN; echo GlassFish UP; } | while read PROC STATUS; do echo -n "$PROC "; printf "%$((48-${#PROC}))s " | tr ' ' -; echo " [$STATUS]"; done
JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]

Here's another one:

$ { echo JBoss DOWN; echo GlassFish UP; } | while read PROC STATUS; do echo -n "$PROC "; printf "%$((48-${#PROC}))s " | tr ' ' -; echo " [$STATUS]"; done
JBoss -------------------------------------------- [DOWN]
GlassFish ---------------------------------------- [UP]
绝不服输 2024-10-13 21:12:20

如果您要在某个固定的列号处结束填充字符,那么您可以过度填充并剪切到长度:

# Previously defined:
# PROC_NAME
# PROC_STATUS

PAD="--------------------------------------------------"
LINE=$(printf "%s %s" "$PROC_NAME" "$PAD" | cut -c 1-${#PAD})
printf "%s %s\n" "$LINE" "$PROC_STATUS"

If you are ending the pad characters at some fixed column number, then you can overpad and cut to length:

# Previously defined:
# PROC_NAME
# PROC_STATUS

PAD="--------------------------------------------------"
LINE=$(printf "%s %s" "$PROC_NAME" "$PAD" | cut -c 1-${#PAD})
printf "%s %s\n" "$LINE" "$PROC_STATUS"
倾城月光淡如水﹏ 2024-10-13 21:12:20

具有自动缩放/调整大小方法和示例的简单控制台跨度/填充/填充/填充。

function create-console-spanner() {
    # 1: left-side-text, 2: right-side-text
    local spanner="";
    eval printf -v spanner \'"%0.1s"\' "-"{1..$[$(tput cols)- 2 - ${#1} - ${#2}]}
    printf "%s %s %s" "$1" "$spanner" "$2";
}

示例: create-console-spanner“正在加载图形模块”“[成功]”

现在这是一个全功能颜色-character-terminal-suite 完成与使用扳手打印颜色和样式格式化字符串有关的所有操作。

# Author: Triston J. Taylor <[email protected]>
# Date: Friday, October 19th, 2018
# License: OPEN-SOURCE/ANY (NO-PRODUCT-LIABILITY OR WARRANTIES)
# Title: paint.sh
# Description: color character terminal driver/controller/suite

declare -A PAINT=([none]=`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`);

declare -i PAINT_ACTIVE=1;

function paint-replace() {
    local contents=$(cat)
    echo "${contents//$1/$2}"
}

source <(cat <<EOF
function paint-activate() {
    echo "\$@" | $(for k in ${!PAINT[@]}; do echo -n paint-replace \"\&$k\;\" \"\${PAINT[$k]}\" \|; done) cat;
}
EOF
)

source <(cat <<EOF
function paint-deactivate(){
    echo "\$@" | $(for k in ${!PAINT[@]}; do echo -n paint-replace \"\&$k\;\" \"\" \|; done) cat;    
}
EOF
)

function paint-get-spanner() {
    (( $# == 0 )) && set -- - 0;
    declare -i l=$(( `tput cols` - ${2}))
    eval printf \'"%0.1s"\' "${1:0:1}"{1..$l}
}

function paint-span() {
    local left_format=$1 right_format=$3
    local left_length=$(paint-format -l "$left_format") right_length=$(paint-format -l "$right_format")
    paint-format "$left_format";
    paint-get-spanner "$2" $(( left_length + right_length));
    paint-format "$right_format";
}

function paint-format() {
    local VAR="" OPTIONS='';
    local -i MODE=0 PRINT_FILE=0 PRINT_VAR=1 PRINT_SIZE=2;
    while [[ "${1:0:2}" =~ ^-[vl]$ ]]; do
        if [[ "$1" == "-v" ]]; then OPTIONS=" -v $2"; MODE=$PRINT_VAR; shift 2; continue; fi;
        if [[ "$1" == "-l" ]]; then OPTIONS=" -v VAR"; MODE=$PRINT_SIZE; shift 1; continue; fi;
    done;
    OPTIONS+=" --"
    local format="$1"; shift;
    if (( MODE != PRINT_SIZE && PAINT_ACTIVE )); then
        format=$(paint-activate "$format&none;")
    else
        format=$(paint-deactivate "$format")
    fi
    printf $OPTIONS "${format}" "$@";
    (( MODE == PRINT_SIZE )) && printf "%i\n" "${#VAR}" || true;
}

function paint-show-pallette() {
    local -i PAINT_ACTIVE=1
    paint-format "Normal: &red;red &green;green &blue;blue &magenta;magenta &yellow;yellow &cyan;cyan &white;white &black;black\n";
    paint-format "  Bold: &bold;&red;red &green;green &blue;blue &magenta;magenta &yellow;yellow &cyan;cyan &white;white &black;black\n";
}

要打印颜色,这很简单:paint-format "&red;This is %s\n" red
稍后您可能想要加粗: paint-format "&bold;%s!\n" WOW

paint- 的 -l 选项format 函数测量文本,以便您可以执行控制台字体度量操作。

paint-format 函数的 -v 选项与 printf 的作用相同,但不能与 -l 一起提供

现在进行跨越

paint-span“你好”。 " &blue;world" [注意:我们没有添加换行符终端序列,但文本填充了终端,因此下一行仅显示为换行符终端序列]

,其输出为:

你好......................世界

Simple Console Span/Fill/Pad/Padding with automatic scaling/resizing Method and Example.

function create-console-spanner() {
    # 1: left-side-text, 2: right-side-text
    local spanner="";
    eval printf -v spanner \'"%0.1s"\' "-"{1..$[$(tput cols)- 2 - ${#1} - ${#2}]}
    printf "%s %s %s" "$1" "$spanner" "$2";
}

Example: create-console-spanner "loading graphics module" "[success]"

Now here is a full-featured-color-character-terminal-suite that does everything in regards to printing a color and style formatted string with a spanner.

# Author: Triston J. Taylor <[email protected]>
# Date: Friday, October 19th, 2018
# License: OPEN-SOURCE/ANY (NO-PRODUCT-LIABILITY OR WARRANTIES)
# Title: paint.sh
# Description: color character terminal driver/controller/suite

declare -A PAINT=([none]=`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`);

declare -i PAINT_ACTIVE=1;

function paint-replace() {
    local contents=$(cat)
    echo "${contents//$1/$2}"
}

source <(cat <<EOF
function paint-activate() {
    echo "\$@" | $(for k in ${!PAINT[@]}; do echo -n paint-replace \"\&$k\;\" \"\${PAINT[$k]}\" \|; done) cat;
}
EOF
)

source <(cat <<EOF
function paint-deactivate(){
    echo "\$@" | $(for k in ${!PAINT[@]}; do echo -n paint-replace \"\&$k\;\" \"\" \|; done) cat;    
}
EOF
)

function paint-get-spanner() {
    (( $# == 0 )) && set -- - 0;
    declare -i l=$(( `tput cols` - ${2}))
    eval printf \'"%0.1s"\' "${1:0:1}"{1..$l}
}

function paint-span() {
    local left_format=$1 right_format=$3
    local left_length=$(paint-format -l "$left_format") right_length=$(paint-format -l "$right_format")
    paint-format "$left_format";
    paint-get-spanner "$2" $(( left_length + right_length));
    paint-format "$right_format";
}

function paint-format() {
    local VAR="" OPTIONS='';
    local -i MODE=0 PRINT_FILE=0 PRINT_VAR=1 PRINT_SIZE=2;
    while [[ "${1:0:2}" =~ ^-[vl]$ ]]; do
        if [[ "$1" == "-v" ]]; then OPTIONS=" -v $2"; MODE=$PRINT_VAR; shift 2; continue; fi;
        if [[ "$1" == "-l" ]]; then OPTIONS=" -v VAR"; MODE=$PRINT_SIZE; shift 1; continue; fi;
    done;
    OPTIONS+=" --"
    local format="$1"; shift;
    if (( MODE != PRINT_SIZE && PAINT_ACTIVE )); then
        format=$(paint-activate "$format&none;")
    else
        format=$(paint-deactivate "$format")
    fi
    printf $OPTIONS "${format}" "$@";
    (( MODE == PRINT_SIZE )) && printf "%i\n" "${#VAR}" || true;
}

function paint-show-pallette() {
    local -i PAINT_ACTIVE=1
    paint-format "Normal: &red;red &green;green &blue;blue &magenta;magenta &yellow;yellow &cyan;cyan &white;white &black;black\n";
    paint-format "  Bold: &bold;&red;red &green;green &blue;blue &magenta;magenta &yellow;yellow &cyan;cyan &white;white &black;black\n";
}

To print a color, that's simple enough: paint-format "&red;This is %s\n" red
And you might want to get bold later on: paint-format "&bold;%s!\n" WOW

The -l option to the paint-format function measures the text so you can do console font metrics operations.

The -v option to the paint-format function works the same as printf but cannot be supplied with -l

Now for the spanning!

paint-span "hello " . " &blue;world" [note: we didn't add newline terminal sequence, but the text fills the terminal, so the next line only appears to be a newline terminal sequence]

and the output of that is:

hello ............................. world

情绪失控 2024-10-13 21:12:20

Bash + seq 允许参数扩展

与 @Dennis Williamson 答案类似,但如果 seq 可用,则不需要对填充字符串的长度进行硬编码。以下代码允许将变量作为位置参数传递给脚本:

COLUMNS="${COLUMNS:=80}"
padlength="${1:-$COLUMNS}"
pad=$(printf '\x2D%.0s' $(seq "$padlength") )

string2='bbbbbbb'
for string1 in a aa aaaa aaaaaaaa
do
     printf '%s' "$string1"
     printf '%*.*s' 0 $(("$padlength" - "${#string1}" - "${#string2}" )) "$pad"
     printf '%s\n' "$string2"
     string2=${string2:1}
done

使用 ASCII 代码“2D”而不是字符“-”以避免 shell 将其解释为命令标志。另一个选项是“3D”使用“=”。

如果没有任何 padlength 作为参数传递,上面的代码默认为 80 个字符的标准终端宽度。

要利用 bash shell 变量COLUMNS(即当前终端的宽度),环境变量需要可供脚本使用。一种方法是通过执行前面带有 .(“dot”命令)的脚本来获取所有环境变量,如下所示:

. /path/to/script

或者(更好)在以下情况下显式传递 COLUMNS 变量:执行,像这样:

/path/to/script $COLUMNS

Bash + seq to allow parameter expansion

Similar to @Dennis Williamson answer, but if seq is available, the length of the pad string need not be hardcoded. The following code allows for passing a variable to the script as a positional parameter:

COLUMNS="${COLUMNS:=80}"
padlength="${1:-$COLUMNS}"
pad=$(printf '\x2D%.0s' $(seq "$padlength") )

string2='bbbbbbb'
for string1 in a aa aaaa aaaaaaaa
do
     printf '%s' "$string1"
     printf '%*.*s' 0 $(("$padlength" - "${#string1}" - "${#string2}" )) "$pad"
     printf '%s\n' "$string2"
     string2=${string2:1}
done

The ASCII code "2D" is used instead of the character "-" to avoid the shell interpreting it as a command flag. Another option is "3D" to use "=".

In absence of any padlength passed as an argument, the code above defaults to the 80 character standard terminal width.

To take advantage of the the bash shell variable COLUMNS (i.e., the width of the current terminal), the environment variable would need to be available to the script. One way is to source all the environment variables by executing the script preceded by . ("dot" command), like this:

. /path/to/script

or (better) explicitly pass the COLUMNS variable when executing, like this:

/path/to/script $COLUMNS
南汐寒笙箫 2024-10-13 21:12:20

如果您希望在保持 bash 3.2 兼容(对于 MacOS)的同时获得更多的稳健性,我在这些情况下经常使用与此类似的模式:

local padding_left
local key_align_right
local margin
local padding_right

padding_left=$(printf '%0.1s' ' '{1..9})
key_align_right=$(printf '%0.1s' ' '{1..15}) 
margin=$(printf '%0.1s' ' '{1..10})
padding_right=$(printf '%0.1s' ' '{1..24})

local tools=("key1" "key2" "key3" "key4" "key5" "key6" "bash version")
local versions=("value1" "value2" "value3" "value4" "value5" "value6" "$(bash --version | awk 'NR==1 {print}')")

echo "╔══════════════════════════════════════════════════════════╗"
echo "║                       Key   Values                       ║"
echo "║══════════════════════════════════════════════════════════║"
echo "║         Key:                     Value:                  ║"
echo "║                                                          ║"
for i in "${!tools[@]}"; do
    local value_trim
    value_trim=$(echo "${versions[i]}" | awk '{ print substr($0, 1, '"${#padding_right}"') }' )

    printf "║%s%s%s" "$padding_left" "${tools[i]}" "${key_align_right:${#tools[i]}}" 
    printf "%s%s%s║\n" "${margin}" "${value_trim}" "${padding_right:${#versions[i]}}"
done
echo "╚══════════════════════════════════════════════════════════╝"                

输出:

╔══════════════════════════════════════════════════════════╗
║                       Key   Values                       ║
║══════════════════════════════════════════════════════════║
║         Key:                     Value:                  ║
║                                                          ║
║         key1                     value1                  ║
║         key2                     value2                  ║
║         key3                     value3                  ║
║         key4                     value4                  ║
║         key5                     value5                  ║
║         key6                     value6                  ║
║         bash version             GNU bash, version 3.2.57║
╚══════════════════════════════════════════════════════════╝

它非常冗长,但使用这样的模式,您可以通过在要对齐的变量的右侧或左侧添加诸如 key_align_right 之类的变量来控制右对齐或左对齐,然后添加 "${key_align_right:${#tools[i]}}" 用空格字符串减去对齐变量的长度,从而对齐变量。

您还可以在循环内使用这段逻辑 value_trim=$(echo "${versions[i]}" | awk '{ print substr($0, 1, '"${#padding_right}"') } ' ) 以防止变量超出您的范围。如果您的示例中的表格具有外部边界,一旦超出外部边界,就会在视觉上破坏视图,这将非常有用。该逻辑将打印该值的子字符串,该子字符串不能长于 padding_right 长度。您可以在输出中看到我的 bash 版本值比表的边界长,但不会破坏它。

这还允许您通过调整打印到顶部变量的空格数、调整范围中的最后一个数字来轻松调整填充、边距和最大长度。

If you'd like for a little bit more robustness while keeping things bash 3.2 compliant ( for MacOS) I use a pattern similar to this pretty frequently for these situations:

local padding_left
local key_align_right
local margin
local padding_right

padding_left=$(printf '%0.1s' ' '{1..9})
key_align_right=$(printf '%0.1s' ' '{1..15}) 
margin=$(printf '%0.1s' ' '{1..10})
padding_right=$(printf '%0.1s' ' '{1..24})

local tools=("key1" "key2" "key3" "key4" "key5" "key6" "bash version")
local versions=("value1" "value2" "value3" "value4" "value5" "value6" "$(bash --version | awk 'NR==1 {print}')")

echo "╔══════════════════════════════════════════════════════════╗"
echo "║                       Key   Values                       ║"
echo "║══════════════════════════════════════════════════════════║"
echo "║         Key:                     Value:                  ║"
echo "║                                                          ║"
for i in "${!tools[@]}"; do
    local value_trim
    value_trim=$(echo "${versions[i]}" | awk '{ print substr($0, 1, '"${#padding_right}"') }' )

    printf "║%s%s%s" "$padding_left" "${tools[i]}" "${key_align_right:${#tools[i]}}" 
    printf "%s%s%s║\n" "${margin}" "${value_trim}" "${padding_right:${#versions[i]}}"
done
echo "╚══════════════════════════════════════════════════════════╝"                

Output:

╔══════════════════════════════════════════════════════════╗
║                       Key   Values                       ║
║══════════════════════════════════════════════════════════║
║         Key:                     Value:                  ║
║                                                          ║
║         key1                     value1                  ║
║         key2                     value2                  ║
║         key3                     value3                  ║
║         key4                     value4                  ║
║         key5                     value5                  ║
║         key6                     value6                  ║
║         bash version             GNU bash, version 3.2.57║
╚══════════════════════════════════════════════════════════╝

It is very verbose but using a pattern like this you can control right or left align by adding variables like key_align_right to the right or left of the variable you'd like to align, and then adding "${key_align_right:${#tools[i]}}" to subtract the length of the aligned variable by the string of spaces, aligning the variable.

You can also use this piece of logic inside the loop value_trim=$(echo "${versions[i]}" | awk '{ print substr($0, 1, '"${#padding_right}"') }' ) to keep variables from going passed your bounds. This is extremely helpful if you have something like the table in my example that has an outer bound that once crossed will visually break the view. The logic will print a substring of the value that can be no longer than the padding_right length. You can see in the output that my value of bash version is longer than the bounds of my table, but doesn't break it.

This also allows you to easily adjust the padding, margins and max length by adjusting the the number of spaces printed to the variables at the top, adjusting the last number in the range.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文