bash中是否有办法获取一定长度的子字符串(在终端中占用#字符),同时保留颜色代码?
我想我可以用一些代码解释我的意思更好(假装粗体意味着绿色):
$ # One string is green and another is normal. $ 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 both of them out to show the difference $ echo -e $green_string Foo bar baz buzz. $ echo -e $normal_string Foo bar baz buzz. $ $ # Get a substring of both. $ green_sub=${green_string:0:11} $ normal_sub=${normal_string:0:11} $ $ # Since the special characters are a part of the string, the colored $ # substring (rightfully) has fewer printable characters in it. $ echo -e "$green_sub\e[0m" Foo $ echo -e $normal_sub Foo bar baz $ $ # Is there any built in way of doing something like this: $ green_sub=`some_method $green_string 11` $ normal_sub=`some_method $normal_string 11` $ echo -e "$green_sub\e[0m"; echo -e $normal_sub Foo bar baz Foo bar baz
对于像我这样的人来说,这是一个复制/粘贴版本:
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_sub\e[0m"
echo -e $normal_sub
# green_sub=`some_method $green_string 11`
# normal_sub=`some_method $normal_string 11`
# echo -e "$green_sub\e[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"
}
此代码有效,但 soooo slow 。
请告诉我有更快/更简单的方法!
答案 0 :(得分:0)
使用正则表达式跳过ANSI序列,仅捕获“普通”文本。下面是一个正则表达式的示例,它捕获(可见)字符串的前5个字符,应用于常规字符串和绿色字符串。
$ regex='\e\[[^m]*m(.{5}).*\e\[0m'
$ for str in '\e[1;32mFoo bar baz\e[0m' 'Foo bar baz'; do
> [[ $str =~ $regex ]] && substr=${BASH_REMATCH[1]}
> echo "$substr"
> done
Foo b
Foo b