一致するパターンを一覧表示ptrn
し、リストの前にファイル名を印刷する次のコードがあります(コンテキストオプションを使用-C NUM
)。
find "$fdir" "${isufx[*]}" -type f -exec bash -c \
"grep --color -l '$ptrn' '{}'; grep --color -ni ${ictx[*]} '$ptrn' '{}'" \;
モンスターという点には同意します。通話を削除することにしました。bash -c
結果は次のとおりです。
OFS=$IFS
IFS=$'\n'
for f in $(find "$fdir" ${isufx[*]} -type f); do
grep -l "$ptrn" "$f" && grep -ni ${ictx[*]} "$ptrn" "$f"
done
IFS=$OFS
上記の提案はありますか?ファイル名の上と下に空白行を使用して、および==>
間に囲まれたリストの前にファイル名を印刷したいと思います。<==
屋根の出力防止の提案の後、次のような結果find
が出ました。
find "$fdir" ${isufx[*]} -type f |
while read f; do
grep -l "$ptrn" "$f" && grep -ni ${ictx[*]} "$ptrn" "$f"
done
答え1
私はあなたがこの答えが好きではないと確信しています。しかし、これはㅏこれを行う正しい方法(いいえ。これ正しい方法ですが、多くの方法の1つだけです)。標準ツール(grepなど)が目的の操作を正確に実行できない場合に独自のカスタムツールを作成することについて疑問に思う人のために、ここに例があります。これがUNIXが使用した方法です。 (また、grepのGREP_COLORS変数を解析して使用するのがどれほど難しいかを知りたかったので...かなり簡単であることがわかりました。)
find ... -exec
これは一度だけフォークするだけで、複数回渡すのではなく、各ファイルに対してすべての操作を一度に実行するスクリプトです。それは扱うどの改行やその他のスペースを含む名前でも有効なファイル名です。
perl
たとえば、次のスクリプトをとして保存しcontext-grep.pl
て実行可能にしますchmod +x context.pl
。次に、次のように実行します。
find "$fdir" "${isufx[*]}" -type f -exec ./context-grep.pl {} +
次の環境変数を使用します。
$ptrn
検索モード用$NUM
印刷するコンテキスト行数(オプション、デフォルト値3)$GREP_COLOR
または$GREP_COLORS
同じカラーコードを使用しますgrep
(オプション、デフォルトは緑色)。
通常どおりコマンドラインで指定できます。
NUM=5 ptrn='foo.*bar' find "$fdir" "${isufx[*]}" -type f -exec ./context-grep.pl {} +
スクリプトの正しいオプション処理は、Perlの多くのオプション処理モジュールの1つを使用して実行できます(例:GetSelect::標準またはGetopt::長い)しかし、このスクリプトはこのウェブサイトに比べてすでに長すぎます。find
使用せずにPerlですべてを書くことができます。ファイル::検索基準寸法。 3つのモジュールはすべてコアPerlライブラリモジュールであり、Perlに含まれています。
#!/usr/bin/perl
use strict;
# This script should use TERM::TERMCAP to get the actual
# colour codes for the current $TERM from the terminfo
# database, but I'll just hard-code it to use ANSI colour
# codes because almost everything is ansi-compatible these days.
# That's good enough for grep, so it's good enough for this.
###
### variable setup and related stuff
###
my $sgr0 = "\033[m\017";
my $colour = "\033[01;32m"; # default to green
# If either of grep's colour env vars are defined, use
# them instead. (the newer $GREP_COLORS is checked last,
# so has precedence over $GREP_COLOR)
if ($ENV{'GREP_COLOR'}) {
$colour = "\033[$ENV{'GREP_COLOR'}m";
};
if ($ENV{'GREP_COLORS'}) {
# e.g. ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36
# This script really only cares about the ms value
# It wouldn't be hard to make it use `mc` as well to print the
# context lines in a different colour than the match line.
my @GC = split /:/, $ENV{'GREP_COLORS'};
foreach (@GC) {
if (m/^ms/) {
my (undef,$c) = split /=/;
$colour = "\033[${c}m";
last;
}
};
};
my $search=$ENV{'ptrn'};
my @context;
my $NUM=3; # default to 3 lines of context
$NUM = $ENV{'NUM'} if (defined($ENV{'NUM'}));
my $last = -1;
my $first_match=1;
###
### main loop, process the input file(s)
###
while(<>) {
chomp;
if ($. <= $last) {
# current line is an AFTER context line, print it
printf "%s%s%s\n", $colour, $_, $sgr0;
} elsif (m/$search/) {
# We've found a match! handle it.
# print filename like head & tail does if this is the
# first match we've found in the current file.
if ($first_match) {
printf "\n==> %s <==\n\n", $ARGV;
$first_match=0;
};
# print the remembered BEFORE context lines
foreach my $l (@context) {
printf "%s%s%s\n", $colour, $l, $sgr0;
};
# print current line
printf "%s%s%s\n", $colour, $_, $sgr0;
# clear the context array
@context=();
# set $last so we can print the AFTER context lines
$last = $. + $NUM;
} else {
# remember the last $NUM lines of context
push @context, $_; # add current C line
shift @context if ($#context >= $NUM); # remove first C line
};
# reset $last, $first_match, and the input record counter
# ($. - equivalent to awk's NR) on every EOF
if (eof) {
close(ARGV);
$last = -1;
$first_match=1;
};
};
エラー:エラー処理がまったくありません。またはオプションの処理。またはヘルプ/使用メッセージ。またはPOD文書。これらは読者に練習問題として残す。
出力例(スクリプト自体の一致行と「チョップ」パターンを囲むコンテキストの2行):
$ NUM=2 ptrn=chomp find . -type f -name '*.pl' -exec ./context-grep.pl {} +
==> ./context-grep.pl <==
while(<>) {
chomp;
if ($. <= $last) {
export GREP_COLOR='0;33'
すべてのマッチ~/.bashrc
ラインとコンテキストラインは黄色で印刷されます。ファイル名は、端末のデフォルトのテキスト色(黒の背景に白)で印刷されます。
答え2
grep
なしで他の解決策を思い出しましたfind
。
echo ""
grep -rl ${isufx[@]} "$ptrn" $fdir |
while read f; do
echo -e $(tput setaf 46)"==> $f <==\n"$(tput sgr0)
grep -ni ${ictx[@]} "$ptrn" "$f"
echo ""
done