2016-05-23 11 views
1

カラーコードを保存しながら、ある長さの部分文字列を取得する方法はありますか?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の出力を受け取り、端末の1行(またはそれよりも短い)を正確に1つの行に塗りつぶす機能を作った:

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

正規表現を使用して、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 
+0

これは複数のカラーコードを含む文字列にどのように適用できますか? "\ e [1; 32mGreen \ e [0m and \ e [1; 31mRed \ e [0m" –

+0

]基本的に、文字列を解析する必要があります。色付けされた文字列がどのように見えるかについての特定の標準はありません。これらのバイトはマークアップタグではありません。次のテキストをどのように表示するかを変更するための指示です。 – chepner