我正在开发一个UNIX机器,并尝试运行一个应用程序,它为标准输出提供了一些调试日志。我已将此输出重定向到日志文件,但现在希望获取显示错误的行。
我的问题在于这是一个简单的
cat output.log | grep FAIL
没有帮助。因为这只显示了其中包含FAIL的行。我想要更多的信息。就像这条线上方的2-3条线路一样失败。有没有办法通过一个简单的shell命令来做到这一点?我想有一个命令行(可以有管道)来执行上述操作。
答案 0 :(得分:9)
grep -C 3 FAIL output.log
请注意,这也会消除useless use of cat (UUOC)。
答案 1 :(得分:5)
grep -A $ NUM
这将在匹配后打印$ NUM行的尾随上下文。
-B $ NUM打印前导上下文。
man grep是你最好的朋友。
所以在你的情况下:
cat log | grep -A 3 -B 3 FAIL
答案 2 :(得分:3)
我有两个我称之为sgrep
的实现,一个在Perl中,一个使用pre-Perl(pre-GNU)标准Unix命令。如果你有GNU grep
,你就不需要这些了。处理前向和后向上下文搜索会更复杂,但这可能是一项有用的练习。
Perl解决方案:
#!/usr/perl/v5.8.8/bin/perl -w
#
# @(#)$Id: sgrep.pl,v 1.6 2007/09/18 22:55:20 jleffler Exp $
#
# Perl-based SGREP (special grep) command
#
# Print lines around the line that matches (by default, 3 before and 3 after).
# By default, include file names if more than one file to search.
#
# Options:
# -b n1 Print n1 lines before match
# -f n2 Print n2 lines following match
# -n Print line numbers
# -h Do not print file names
# -H Do print file names
use strict;
use constant debug => 0;
use Getopt::Std;
my(%opts);
sub usage
{
print STDERR "Usage: $0 [-hnH] [-b n1] [-f n2] pattern [file ...]\n";
exit 1;
}
usage unless getopts('hnf:b:H', \%opts);
usage unless @ARGV >= 1;
if ($opts{h} && $opts{H})
{
print STDERR "$0: mutually exclusive options -h and -H specified\n";
exit 1;
}
my $op = shift;
print "# regex = $op\n" if debug;
# print file names if -h omitted and more than one argument
$opts{F} = (defined $opts{H} || (!defined $opts{h} and scalar @ARGV > 1)) ? 1 : 0;
$opts{n} = 0 unless defined $opts{n};
my $before = (defined $opts{b}) ? $opts{b} + 0 : 3;
my $after = (defined $opts{f}) ? $opts{f} + 0 : 3;
print "# before = $before; after = $after\n" if debug;
my @lines = (); # Accumulated lines
my $tail = 0; # Line number of last line in list
my $tbp_1 = 0; # First line to be printed
my $tbp_2 = 0; # Last line to be printed
# Print lines from @lines in the range $tbp_1 .. $tbp_2,
# leaving $leave lines in the array for future use.
sub print_leaving
{
my ($leave) = @_;
while (scalar(@lines) > $leave)
{
my $line = shift @lines;
my $curr = $tail - scalar(@lines);
if ($tbp_1 <= $curr && $curr <= $tbp_2)
{
print "$ARGV:" if $opts{F};
print "$curr:" if $opts{n};
print $line;
}
}
}
# General logic:
# Accumulate each line at end of @lines.
# ** If current line matches, record range that needs printing
# ** When the line array contains enough lines, pop line off front and,
# if it needs printing, print it.
# At end of file, empty line array, printing requisite accumulated lines.
while (<>)
{
# Add this line to the accumulated lines
push @lines, $_;
$tail = $.;
printf "# array: N = %d, last = $tail: %s", scalar(@lines), $_ if debug > 1;
if (m/$op/o)
{
# This line matches - set range to be printed
my $lo = $. - $before;
$tbp_1 = $lo if ($lo > $tbp_2);
$tbp_2 = $. + $after;
print "# $. MATCH: print range $tbp_1 .. $tbp_2\n" if debug;
}
# Print out any accumulated lines that need printing
# Leave $before lines in array.
print_leaving($before);
}
continue
{
if (eof)
{
# Print out any accumulated lines that need printing
print_leaving(0);
# Reset for next file
close ARGV;
$tbp_1 = 0;
$tbp_2 = 0;
$tail = 0;
@lines = ();
}
}
Pre-Perl Unix解决方案(使用普通ed
,sed
和sort
- 虽然它使用的getopt
当时不一定可用,但是:
#!/bin/ksh
#
# @(#)$Id: old.sgrep.sh,v 1.5 2007/09/15 22:15:43 jleffler Exp $
#
# Special grep
# Finds a pattern and prints lines either side of the pattern
# Line numbers are always produced by ed (substitute for grep),
# which allows us to eliminate duplicate lines cleanly. If the
# user did not ask for numbers, these are then stripped out.
#
# BUG: if the pattern occurs in in the first line or two and
# the number of lines to go back is larger than the line number,
# it fails dismally.
set -- `getopt "f:b:hn" "$@"`
case $# in
0) echo "Usage: $0 [-hn] [-f x] [-b y] pattern [files]" >&2
exit 1;;
esac
# Tab required - at least with sed (perl would be different)
# But then the whole problem would be different if implemented in Perl.
number="'s/^\\([0-9][0-9]*\\) /\\1:/'"
filename="'s%^%%'" # No-op for sed
f=3
b=3
nflag=no
hflag=no
while [ $# -gt 0 ]
do
case $1 in
-f) f=$2; shift 2;;
-b) b=$2; shift 2;;
-n) nflag=yes; shift;;
-h) hflag=yes; shift;;
--) shift; break;;
*) echo "Unknown option $1" >&2
exit 1;;
esac
done
pattern="${1:?'No pattern'}"
shift
case $# in
0) tmp=${TMPDIR:-/tmp}/`basename $0`.$$
trap "rm -f $tmp ; exit 1" 0
cat - >$tmp
set -- $tmp
sort="sort -t: -u +0n -1"
;;
*) filename="'s%^%'\$file:%"
sort="sort -t: -u +1n -2"
;;
esac
case $nflag in
yes) num_remove='s/[0-9][0-9]*://';;
no) num_remove='s/^//';;
esac
case $hflag in
yes) fileremove='s%^$file:%%';;
no) fileremove='s/^//';;
esac
for file in $*
do
echo "g/$pattern/.-${b},.+${f}n" |
ed - $file |
eval sed -e "$number" -e "$filename" |
$sort |
eval sed -e "$fileremove" -e "$num_remove"
done
rm -f $tmp
trap 0
exit 0
sgrep
的shell版本于1989年2月编写,并于1989年5月修复。除了1997年至2007年的行政变更(SCCS到RCS过渡)之外,它保持不变,当时我添加{ {1}}选项。我在2007年改用了Perl版本。
答案 3 :(得分:1)
$ grep --context 3 FAIL output.log
$ grep --help | grep context
-B, --before-context=NUM print NUM lines of leading context -A, --after-context=NUM print NUM lines of trailing context -C, --context=NUM print NUM lines of output context -NUM same as --context=NUM
答案 4 :(得分:1)
http://thedailywtf.com/Articles/The_Complicator_0x27_s_Gloves.aspx
您可以使用sed
打印特定行,假设您想要第20行
sed '20 p' -n
FILE_YOU_WANT_THE_LINE_FROM
完成。
-n可防止文件中的回显行。引号中的部分是要应用的sed
规则,它指定您希望规则应用于第20行,并且您要打印。