2016-05-23 17 views
1

Gibt es einen Weg in bash, um einen Teilstring mit einer bestimmten Länge (als # Zeichen im Terminal nimmt) zu erhalten, während Farbcodes erhalten bleiben?Bash - Get Teilstring mit Farbcodes

Ich glaube, ich kann erklären, was ich meine besser mit einigem Code (fett Mittel grün vorgeben):

 
$ # 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 

Für Leute wie mich, hier ist eine copy/paste-Version:

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 

I hat eine Funktion erstellt, die zu Kopier-/Pastendemonstrationszwecken die Ausgabe von ls nimmt und sie genau eine Zeile des Terminals (oder kürzer) füllt:

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" 
} 

Dieser Code funktioniert, aber es ist so langsam.

Bitte sagen Sie mir, es gibt einen schnelleren/einfacheren Weg, dies zu tun!

Antwort

0

Verwenden Sie einen regulären Ausdruck, um die ANSI-Sequenzen zu überspringen und nur den "normalen" Text zu erfassen. Hier sehen Sie ein Beispiel für einen regulären Ausdruck, der die ersten 5 Zeichen der (sichtbaren) Zeichenfolge erfasst, die sowohl auf eine normale als auch auf eine grüne Zeichenfolge angewendet wird.

$ 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

Wie kann dies auf eine Zeichenfolge mit mehreren Farbcodes angewendet werden? "\ e [1; 32mGreen \ e [0m und \ e [1; 31mRed \ e [0m" –

+0

Im Wesentlichen müssen Sie die Zeichenkette analysieren, die keine starke Farbe einer Shell-Sprache ist. Es gibt keinen bestimmten Standard dafür, wie eine farbige Zeichenfolge aussehen sollte. Diese Bytes sind keine Markup-Tags. sie sind nur Anweisungen an ein Terminal, um zu ändern, wie es den folgenden Text anzeigt. – chepner