bash中有没有一种方法可以在保留颜色代码的同时获得一定长度的子字符串(作为它在终端中占用的#字符)?
我想我可以用一些代码更好地解释我的意思(假装粗体表示绿色):
$#一个字符串为绿色,另一个为正常字符串。$green_string="\e[1;32mFoo bar baz buzz.\e[0]"$normal_string=`echo-e$green_string | sed-r"s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g"`$$#将两者回声显示出来以显示差异$echo-e$green_stringFoo酒吧巴兹嗡嗡作响$echo-e$normal_stringFoo酒吧巴兹嗡嗡作响。$$#获取两者的子字符串。$green_sub=${green_string:0:11}$normal_sub=${normal_string:0:11}$$#由于特殊字符是字符串的一部分$#子字符串(正确地说)中的可打印字符较少。$echo-e"$green_sub\e[0]">Foo$echo-e$normal_subFoo bar baz$$#有没有这样的内置方式:$green_sub=`some_method$green_string 11`$normal_sub=`some_method$normal_string 11`$echo-e"$green_sub\e[0]";echo-e$normal_subFoo-barbazFoo-barbiz
对于像我这样的人来说,这里有一个复制/粘贴版本:
green_string="e[1;32mFoo bar baz buzz.e[0m"
normal_string=`echo -e $green_string | sed -r "s/x1B[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g"`
echo -e $green_string
echo -e $normal_string
green_sub=${green_string:0:11}
normal_sub=${normal_string:0:11}
echo -e "$green_sube[0m"
echo -e $normal_sub
# green_sub=`some_method $green_string 11`
# normal_sub=`some_method $normal_string 11`
# echo -e "$green_sube[0m"; echo -e $normal_sub
我做了一个函数,为了复制/粘贴演示的目的,它接收ls的输出,并使其正好填满终端的一行(或更短):
function lsline {
color_out=$( ls --color=always | tr "n" " " )
max_len=`tput cols`
cur_len=0
is_esc=0
# This is the build of the final string that will be printed out.
build=""
# This is the build of any escape sequence so I know not to
# include it in the substring count
esc_build=""
for (( i=0; i<${#color_out}; i++ )); do
char="${color_out:$i:1}"
# Is there an easier way to check if a char is an escape character?
code=$( printf %x "'$char" )
# Currently in an escape sequence, so don't count towards max length.
if [ "$is_esc" -eq "1" ]; then
esc_build="$esc_build$char"
if [ "$char" = "m" ]; then
is_esc=0
build="$build$esc_build"
esc_build=""
fi
elif [ "$code" = "1b" ]; then
# 27 is escape character.
is_esc=1
esc_build="$char"
else
# Not an escape sequence, so build our normal string and update
# the current substring length.
build="$build$char"
((cur_len++))
if [ "$cur_len" -eq "$max_len" ]; then
build="$build$( tput sgr0 )"
break
fi
fi
done
echo "$build"
}
这段代码很有效,但速度太慢了。
请告诉我有一种更快/更容易的方法!
使用正则表达式跳过ANSI序列,只捕获"普通"文本。下面是一个正则表达式的示例,它捕获(可见)字符串的前5个字符,同时应用于正则字符串和绿色字符串。
$ regex='e[[^m]*m(.{5}).*e[0m'
$ for str in 'e[1;32mFoo bar baze[0m' 'Foo bar baz'; do
> [[ $str =~ $regex ]] && substr=${BASH_REMATCH[1]}
> echo "$substr"
> done
Foo b
Foo b