gpt4 book ai didi

bash - 使用 bash/printf 打印和填充字符串

转载 作者:行者123 更新时间:2023-12-05 03:18:21 29 4
gpt4 key购买 nike

在 bash 脚本中,我喜欢使用 printf "%-20s""some string" 来创建排列的列。这适用于常规文本,但不适用于多字节 unicode,也不适用于任何类型的终端修饰。

效果很好:

for i in string longer_string Some_kind_of_monstrosity ; do
printf "%-20s" $i ; echo " OK"
done

一切都安排得很好:

string               OK
longer_string OK
Some_kind_of_monstrosity OK

但是 - 它不适用于多字节 unicode 或颜色代码:

printred () { tput setaf 1; printf %b "$*"; tput sgr0; }
printf "%-20s" test ; echo " NOK"
printf "%-20s" $(printred RED) ; echo " NOK"
printf "%-20s" "★★★★" ; echo " NOK"

看起来 bash 内置 printf 和 coreutils/printf 都只是计算字符串中的字节数,而不是输出中可见的字符数:

test                 NOK
RED NOK
★★★★ NOK

有没有办法在 bash 中很好地实现这一点? (我使用的是 bash 5.0.17,但我不反对使用其他工具。)

最佳答案

这是我为 utf-8 兼容的字符串对齐编写的示例库:

align.sh:

#!/bin/false
# UTF-8-compatible string alignment library

# Space pad align string to width
# @params
# $1: The alignment width
# $2: The string to align
# @stdout
# aligned string
align::left() {
local -i width=${1:?} # Mandatory column width
local -- str=${2:?} # Mandatory input string
local -i length=$((${#str} > width ? width : ${#str}))
local -i pad_right=$((width - length))
printf '%s%*s' "${str:0:length}" $pad_right ''
}
align::right() {
local -i width=${1:?} # Mandatory column width
local -- str=${2:?} # Mandatory input string
local -i length=$((${#str} > width ? width : ${#str}))
local -i offset=$((${#str} - length))
local -i pad_left=$((width - length))
printf '%*s%s' $pad_left '' "${str:offset:length}"
}
align::center() {
local -i width=${1:?} # Mandatory column width
local -- str=${2:?} # Mandatory input string
local -i length=$((${#str} > width ? width : ${#str}))
local -i offset=$(((${#str} - length) / 2))
local -i pad_left=$(((width - length) / 2))
local -i pad_right=$((width - length - pad_left))
printf '%*s%s%*s' $pad_left '' "${str:offset:length}" $pad_right ''
}

演示:

#!/usr/bin/env bash

# Demonstrates the align library
. ./align.sh

strings=(
'Früchte und Gemüse'
'Milchprodukte'
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
)

printf '%s\n' 'Left-aligned:'
for str in "${strings[@]}"; do
printf "| %s |\n" "$(align::left 20 "$str")"
done
printf '\n%s\n' 'Right-aligned:'
for str in "${strings[@]}"; do
printf "| %s |\n" "$(align::right 20 "$str")"
done
printf '\n%s\n' 'Center-aligned:'
for str in "${strings[@]}"; do
printf "| %s |\n" "$(align::center 20 "$str")"
done

演示输出:

Left-aligned:
| Früchte und Gemüse |
| Milchprodukte |
| ABCDEFGHIJKLMNOPQRST |

Right-aligned:
| Früchte und Gemüse |
| Milchprodukte |
| GHIJKLMNOPQRSTUVWXYZ |

Center-aligned:
| Früchte und Gemüse |
| Milchprodukte |
| DEFGHIJKLMNOPQRSTUVW |

关于bash - 使用 bash/printf 打印和填充字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73742856/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com