Grep หลากสี


30

ฉันพยายามเรียกคำสั่ง grep แต่ละคำเพื่อเน้นว่าผลลัพธ์เป็นสีที่ต่างกัน ฉันสามารถทำได้ด้วยตนเองโดยใช้บรรทัดดังนี้:

ls -l GREP_COLORS='mt=01;32' grep c | GREP_COLORS='mt=01;31' grep o | GREP_COLORS='mt=01;34' grep n | GREP_COLORS='mt=01;36' grep f

cตัวละครทุกตัวจะถูกเน้นด้วยสีเขียวและoตัวละครทุกตัวจะถูกเน้นด้วยสีแดง ฯลฯ ...

เพื่อให้ตัวอย่างนี้ทำงานคุณจะต้องแน่ใจว่าคุณมี --color=alwaysคำสั่ง grep อยู่เสมอ ฉันได้ตั้งค่านี้ใน.bashrc grep ของฉันดังนั้นจะมีสี:

export GREP_OPTIONS='--color=always'


สิ่งที่ฉันพยายามทำให้สำเร็จคือห่อฟังก์ชันนี้ด้วยนามแฝงเพื่อให้ฉันสามารถโทรได้ grepและมีGREP_COLORSค่าที่แตกต่างกันในแต่ละครั้ง ฉันเข้าใจการพิจารณาของเชลล์จำนวนมากสำหรับ grep piped ใหม่แต่ละอันและฉันพยายามทำสิ่งนี้โดยการสร้างไฟล์บางไฟล์ (หนึ่งสำหรับแต่ละสี) เพื่อระบุว่าพวกมันถูกใช้ไปแล้ว

ฉันได้พยายามมาบ้างแล้ว แต่ก็แปลกแล้วอันนี้ดูเหมือนจะทำงานได้ดีที่สุด ฉันมีสิ่งนี้ในของฉัน.bashrc :

alias mg="mygrep"
mygrep(){
    # define possible colors
    COLORS=("01;32" "01;31" "01;34" "01;36")
    COUNTER=0
    NUM=0
    # as long as the color has already been used, keep searching
    while [ -f /home/lior/Desktop/mygrep_$NUM ]; do
        # get a random index
        let NUM=`shuf --input-range=0-$(( ${#COLORS[*]} - 1 )) | head -1`
        wait ${!}
        $(( COUNTER+=1 ))
        if [ "$COUNTER" -ge ${#COLORS[@]} ]; then
            # remove all color locks
            rm /home/lior/Desktop/mygrep_*
            wait ${!}
        fi
    done
    # mark this color as used
    touch /home/lior/Desktop/mygrep_$NUM
    wait ${!}

    # lets go!
    GREP_COLORS="mt=${COLORS[$NUM]}" grep "$@"
}

ฉันใช้นามแฝงเช่นนี้:

ll | mg c | mg o | mg n | mg f

ผลลัพธ์ค่อนข้างเย็น อย่างไรก็ตามมีข้อผิดพลาดบางอย่างที่แตกต่างกันเล็กน้อยในแต่ละครั้ง นี่คือภาพหน้าจอสองสามภาพ:

ดูเหมือนว่าเชลล์จะผ่านแต่ละคำสั่งไพพ์ฟังก์ชันก่อนหน้านี้ยังไม่เสร็จสิ้นการดำเนินการ พยายามลบไฟล์ที่ไม่มีอยู่อีกต่อไป ฉันไม่แน่ใจว่าcommand not foundข้อผิดพลาดอื่น ๆมาจากที่ใด

อย่างที่คุณเห็นฉันมีบางอย่าง waitคำสั่งเพื่อให้การจัดการไฟล์เสร็จสมบูรณ์ แต่สิ่งนี้ดูเหมือนจะไม่ทำงานได้ดีเกินไป อีกสิ่งที่ฉันได้ลองแล้วคือการใช้หน่วยความจำที่ใช้ร่วมกัน/dev/shmแต่ให้ผลลัพธ์ที่คล้ายกัน

ฉันจะไปเกี่ยวกับการรับผลลัพธ์ที่ฉันต้องการได้อย่างไร

บันทึก:

ฉันกำลังมองหาคำตอบที่แค่หุ้มคำสั่ง grep เพราะมันมีฟังก์ชั่นมากมายที่ฉันต้องการใช้และตั้งใจจะใส่ตรรกะอื่น ๆ ระหว่างไพพ์ดังนั้นฉันจึงไม่ต้องการให้คำค้นหาทั้งหมดพร้อมกัน ฉันไม่ต้องการเครื่องมืออื่น ๆ เช่น "grep like" ขออภัยที่@terdonผู้ได้โพสต์คำแนะนำที่ยอดเยี่ยมไว้แล้ว


ตัวอย่างแรกของคุณไม่ตรงกับสิ่งที่คุณกำลังอธิบายในส่วนที่เหลือเพียงแค่พูด
แบร์นฮาร์ด

@bernhard ฉันไม่เข้าใจสิ่งที่คุณหมายถึง .. ความตั้งใจของผมคือการใช้นามแฝงของฉันเป็นส่วนหนึ่งของคำสั่งที่ใหญ่กว่าโดยใช้ท่อ ... โปรดแจ้งให้เรารู้ว่าสิ่งที่ขัดแย้งคุณกำลังพูดถึง ...
Lix

ฉันคิดว่าคุณต้องการใช้นามแฝงของคุณนอกท่อด้วย อย่างไรก็ตามตัวอย่างแรกของคุณไม่ได้ผลสำหรับฉัน คุณลองalias mg="mygrep; grep"ไหม
แบร์นฮาร์ด

@Bernhard - ฉันกำลังทำงานบนกล่อง Ubuntu 12.04 ฉันจะไม่แปลกใจหากมีความแตกต่างเล็กน้อย ... ฉันลองทำตามคำแนะนำของคุณปัญหาที่เกิดขึ้นก็คือmygrep;คำสั่งใหม่ในตัวของมันเองและกระแสข้อมูลก็หายไป ไปป์ที่เข้ามาจากlsจะถูกส่งผ่านไปยังmygrep;และไม่ให้ grep อย่างน้อยนั่นเป็นวิธีที่ฉันเข้าใจ
Lix

@Bernhard - อ่า .. ฉันคิดว่าฉันรู้ว่าทำไมมันไม่ได้ผลสำหรับคุณ คุณต้องแน่ใจว่าคุณมี--color=alwaysคำสั่ง grep ทั้งหมดของคุณ .bashrcฉันได้ตั้งที่ทั่วโลกในของฉัน ฉันแก้ไขที่โพสต์
Lix

คำตอบ:


6

นี่คือวิธีการที่แตกต่างกัน ฉันมีสคริปต์ Perl เล็กน้อยที่ฉันได้โพสต์แล้วในคำตอบอื่นที่จะเน้นผู้ใช้ให้รูปแบบในสีที่ต่างกัน สคริปต์ที่แก้ไขแล้วจะมีลักษณะgrepดังนี้:

#!/usr/bin/env perl
use Getopt::Std;
use strict;
use Term::ANSIColor; 

my %opts;
getopts('hic:l:',\%opts);
    if ($opts{h}){
      print<<EoF; 
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

EoF
      exit(0);
    }

my $case_sensitive=$opts{i}||undef;
my @color=('bold red','bold blue', 'bold yellow', 'bold green', 
       'bold magenta', 'bold cyan', 'yellow on_blue', 
       'bright_white on_yellow', 'bright_yellow on_red', 'white on_black');
if ($opts{c}) {
   @color=split(/,/,$opts{c});
}
my @patterns;
if($opts{l}){
     @patterns=split(/,/,$opts{l});
}
else{
    $patterns[0]='\*';
}

# Setting $| to non-zero forces a flush right away and after 
# every write or print on the currently selected output channel. 
$|=1;

while (my $line=<>) 
{ 
    my $want=0;
    for (my $c=0; $c<=$#patterns; $c++){
    if($case_sensitive){
        if($line=~/$patterns[$c]/){
           $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ge;
           $want++;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
          $want++;
        }
      }
    }
print STDOUT $line if $want>0;
}

หากคุณบันทึกสคริปต์นั้นไว้ที่cgrepใดที่หนึ่งของคุณPATHและทำให้สามารถเรียกใช้งานได้คุณสามารถระบุรูปแบบที่แตกต่างกันได้ถึง 10 รูปแบบโดยแต่ละรูปแบบจะพิมพ์ด้วยสีที่ต่างกัน:

ป้อนคำอธิบายรูปภาพที่นี่

$ cgrep -h
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

5

การเรียกใช้grepในไปป์แต่ละครั้งจะทำงานในเชลล์แยกต่างหากดังนั้นคุณจะต้องผ่านบางสถานะระหว่างกัน วิธีแก้ปัญหาต่อไปนี้เป็นวิธีที่หยาบคายในการจัดการกับไฟล์ที่เก็บดัชนีสีและไฟล์ล็อคซึ่งทำให้มั่นใจได้ว่าการโทรพร้อมกันจะไม่อ่านค่าเดียวกัน:

#!/usr/bin/env bash
color_index_file=~/.gitcolor
color_index_lock_file=/tmp/$(basename $0)

colors=()
for index in {31..34}
do
    colors+=("01;$index")
done

until mkdir "$color_index_lock_file" 2>/dev/null
do
    :
done

color_index=$(($(cat "$color_index_file" || echo 0) + 1))

if [[ $color_index -ge ${#colors[@]} ]]
then
    color_index=0
fi

printf "$color_index" > "$color_index_file"
rmdir "$color_index_lock_file"

GREP_COLORS="mt=01;${colors[$color_index]}" grep --color=always "$@"

ทดสอบสมมติว่าคุณได้ตั้งชื่อสำเนาของคุณcgrepและวางลงบนPATH:

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz

ตัวแปรเดียวที่จำเป็นต้องได้รับการบำรุงรักษาคือCOLOR_INDEXและGREP_COLORS. ฉันพยายามส่งออกสิ่งเหล่านี้เมื่อสิ้นสุดฟังก์ชั่นโดยไม่สำเร็จ นั่นคือสิ่งที่คุณหมายถึงอะไร เพียงแค่มีexport VARใช่มั้ย
Lix

โอ้ - และอือ .. typo COLOR_TOGGLEโง่ที่นั่นด้วย ขอขอบคุณสำหรับการจับมัน :)
Lix

1
@ l0b0 การส่งออกไม่ได้ผลสำหรับฉันเช่นกันต้องลงคะแนนตอนนี้จนกว่าจะตอบคำถามจริงๆ
แบร์นฮาร์ด

@Bernhard ใช้งานได้กับคุณหรือไม่
l0b0

ขอบคุณสำหรับข้อมูลของคุณ! ฉันได้รวมgrep "$@"ข้อเสนอแนะของคุณ- ที่แยกออกนามแฝงเพื่อเรียกใช้ฟังก์ชั่นแล้ว grep
Lix

1

หากคุณพอใจกับนิพจน์ทั่วไปคุณอาจต้องการตรวจสอบ grc และ grcat grc สาย grcat

grcat ใช้ไฟล์กำหนดค่าที่คุณสามารถเพิ่มนิพจน์ทั่วไปเพื่อจับคู่ข้อความที่จะแสดงในแต่ละสี นอกจากนี้ยังมีตัวเลือกอื่น ๆ อีกมากมาย มันเริ่มต้นที่ colorizing ล็อกไฟล์ของระบบ

ขึ้นอยู่กับสิ่งที่คุณมีในใจสำหรับสคริปต์สุดท้ายของคุณคุณอาจจะสามารถปรับสีผลลัพธ์ของคุณด้วยคำสั่งเดียว

เคล็ดลับคือการระบุ regexes อย่างถูกต้องสำหรับแต่ละ "เขตข้อมูล" ในแหล่งข้อมูลของคุณ จะง่ายกว่านี้มากหากข้อมูลของคุณมีโครงสร้างค่อนข้างสม่ำเสมอ

ครั้งล่าสุดที่ฉันลองฉันไม่ได้ไปไกลเกินไป แต่ฉันอาจจะไปอีกเพราะฉัน regexes ดีกว่าเดิม

นอกจากนี้ยังมีคำสั่ง tput ซึ่งสามารถใช้ในการส่งข้อมูล (เช่นการเปลี่ยนสี) ไปยังอุปกรณ์ปลายทางของคุณโดยตรง

ทั้งสองวิธีมีการโพสต์ด้านล่าง มันพูดเกี่ยวกับคำสั่ง find แต่มันสามารถนำไปใช้กับการส่งออกของคำสั่งใด ๆ

เอาต์พุต FIND สี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.