ソースに色が含まれている場合に、Bash 組み込みの `printf` を使用して列に出力するにはどうすればよいですか?

ソースに色が含まれている場合に、Bash 組み込みの `printf` を使用して列に出力するにはどうすればよいですか?

コードは次のとおりです:

#!/bin/bash
ips[0]='192.168.0.1'
ips[1]='192.168.0'
ips[2]='255.255.255.256'
ips[3]='123.123.123.123.123'
ips[4]='a.b.c.d'
ips[5]='255.255.255.255'
ips[6]='0.0.0.0'
ips[7]='192.168.1.1'
ips[8]='4.2.2.2'

regex="^((25[0-5]|2[0-4][0-9]|[01][0-9][0-9]|[0-9]{1,2})[.]){3}(25[0-5]|2[0-4][0-9]|[01][0-9][0-9]|[0-9]{1,2})$"

regexVar=$(printf "\033[33mSaved in a VARIABLE\033[0m")
regexStr=$(printf "\033[34mIs a STRING\033[0m")
validOut=$(printf "\033[32mValid\033[0m")
invalidOut=$(printf "\033[31mInvalid\033[0m")
noQuotes="NO quotes"
singleQuotes="Single quotes"
doubleQuotes="Double quotes"

printStyle="%-25s %-10s %-20s %-10s\n"
printTitle=$(printf "${printStyle}" "IP Address" "Validity" "Regex" "Quote Type")
print2ndLine=$(printf "${printStyle}" "====================" "==========" "====================" "==========")

function validIP1a() {
    echo "${printTitle}"
    echo "${print2ndLine}"
    for (( i=0; i<${#ips[@]}; i++ )); do
        if [[ "${ips[i]}" =~ $regex ]]; then
            printf "${printStyle}" "${ips[i]}" "${validOut}" "${regexVar}" "${noQuotes}"
        else
            printf "${printStyle}" "${ips[i]}" "${invalidOut}" "${regexVar}" "${noQuotes}"
        fi
    done
}

validIP1a

出力は次のようになります。

出力を揃えることができません

期待される出力は次のとおりです。

期待される整列出力

期待した結果が得られないのはなぜですか? どうすれば解決できますか?

答え1

printfは、色を設定するエスケープ コード内の文字をカウントするため、実際には印刷されない文字を認識しません。固定長のフォーマットされた ( %-20s) 文字列の外側に文字を配置する必要があります。次の 2 つprintfの を比較してください。

#!/bin/bash
green=$'\033[32m'
yellow=$'\033[33m'
normal=$'\033[0m'

printf "1234567890123456789012345678901234567\n";
printf "%-20s %s\n" "${yellow}some string${normal}"  "next col"
printf "${yellow}%-20s${normal} %s\n" "some string"  "next col"

出力は次のようになります。

サンプル出力

もちろん、色を変更できる場合は、別の変数に入れることができます。

printf "%s%-20s${normal} %s\n" "$green" "some string"  "next col"

答え2

validOutおよびの文字数を数えたい場合がありますinvalidOut。私はそれぞれ 10 個以上を数えています。

#                                11   11111
#                    1   2245678901   23456
  validOut=$(printf "\033[32mValid\033[0m")
invalidOut=$(printf "\033[31mInvalid\033[0m")

覚えておいてください、貧弱な人は、printfそれらの文字の一部が見えず、色が変更されることを知ることは不可能です... 少なくとも 10 文字の左揃えのフィールドを要求し、次に 10 文字を超える文字列でそれを埋めようとしました。結果が垂直に揃えられていないのも不思議ではありません。

関連情報