色とりどりのグレップ


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=alwaysgrepコマンドを使用する必要があり ます。私はこれを私の中で設定した.bashrc ので、grepは常に色を持っています:

export GREP_OPTIONS='--color=always'


私が達成しようとしているのは、この機能をエイリアスでラップgrepして、GREP_COLORS毎回呼び出して異なる値を設定できるようにすることです。パイプされた新しいgrepごとに複数のシェルの考慮事項を理解し、いくつかのファイル(各色に1つ)を作成してこれを克服しようとして、既に使用されていることを示します。

私はいくつかの試みをしましたが、奇妙なことに、これは「最高」に機能するようです。私はこれを持っています.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、ファイル操作を完了させるためにいくつかのコマンドを入力しましたが、これはあまりうまく機能していないようです。もう1つ試したのは、共有メモリを使用する/dev/shmことですが、同様の結果が得られました。

必要な結果を得るにはどうすればよいですか?

注意:

使用したい機能がたくさんあり、パイプの間に他のロジックを挿入するつもりなので、単にgrepコマンドをラップする回答を探しています。他の「grep like」ツールも探していません。素晴らしいperlの提案をすでに投稿している@terdonに申し訳ありません。


最初の例は、残りの部分で説明している内容と一致していません。
ベルンハルト

@bernhard私は...私はあなたが話している矛盾何を教えてください...私の意図は、配管を使用して、より大きなコマンドの一部として私のエイリアスを使用することです..あなたが何を意味するか理解していない
LIX

パイプ以外でもエイリアスを使用したいと思っていました。とにかく、あなたの最初の例は私にはうまくいきません。試しましたalias mg="mygrep; grep"か?
ベルンハルト

@Bernhard-私はubuntu 12.04ボックスに取り組んでいます。わずかな違いがあったとしても驚くことはありません...私はあなたの提案を試みましたが、それに関する問題mygrep;はそれ自体で新しいコマンドに変わり、データストリームが失われることです。からの着信パイプはgrepにls渡されmygrep;、grepには渡されません。少なくともそれは私がそれを理解する方法です。
リックス

@Bernhard-ああ。どうしてうまくいかなかったのか知っていると思う。--color=alwaysすべてのgrepコマンドを確実に実行する必要があります。私はそれをグローバルに設定しました.bashrc。これを編集して投稿しました。
リックス

回答:


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_INDEXand のみですGREP_COLORS。関数の最後にこれらをエクスポートしようとしましたが、成功しませんでした。それはあなたが意図したものですか?持っているだけexport VARですよね?
リックス

ああ-そうだねCOLOR_TOGGLE。それをキャッチしてくれてありがとう:)
Lix

1
@ l0b0エクスポートは私にとっても機能しません。質問に本当に答えるまで、今のところダウン票を投じる必要があります。
ベルンハルト

@Bernhardこれはあなたのために働きますか?
l0b0

ご意見ありがとうございます!私はあなたのgrep "$@"提案を取り入れました-エイリアスを整理して関数を実行し、次にgrepを実行します。
リックス

1

正規表現が得意であれば、grcとgrcatを調べてみてください。grcはgrcatを呼び出します。

grcatは、各色で表示されるテキストに一致する正規表現を追加できる構成ファイルを使用します。他にも多くのオプションがあります。デフォルトでは、システムログファイルが色付けされます。

最終的なスクリプトで何を考えているかに応じて、1つのコマンドだけで出力を色付けできる場合があります。

秘Theは、データソースの各「フィールド」に正規表現を正しく指定することです。データの構造が比較的均一であれば、これは非常に簡単です。

前回試したとき、あまり遠くはありませんでしたが、正規表現のほうが当時よりも少し上手だから、もう一度やってみるかもしれません。

端末デバイスに情報(色の変更など)を直接送信するために使用できるtputコマンドもあります。

両方のアプローチは、以下の投稿でカバーされています。findコマンドについて説明していますが、どのコマンドの出力にも適用できます。

色付きのFIND出力?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.