How do I output the previous line of a file after searching for a specific line?
How do I get the previous line of a file after searching for one line?
Example: There is a file called fore.dat containing:
:Server:APBS
:Max Blocking queue:20
:Transport:000
:Server:APBS
:Max Transactions:10
:MaxConnections:1
:Transport:001
:Server:APBS
:Max Transactions:10
:MaxConnections:1
:Transport:005
:Server:BIT
:Max Transactions:10
:Max Connections:1
:Transport:004
:Server:APBS
:Max Transactions:44440
:开发者_开发问答Max Connections:1
:Transport:002
:Server:BET
:Max Transactions:10
:Max Connections:1
:Transport:003
:Server:APBS
:Max Transactions:50
:Max Connections:1
I want to print the Transport number containing server name as APBS. i.e; the output as:
:Transport:000
:Transport:001
:Transport:004
:Transport:003
This looks like a job for awk
and it should even work on AIX where you don't have gawk
...
% awk -F':' '
/^:Transport:/ {
transport = $0
}
NF == 3 && $2 == "Server" && $3 == "APBS" {
printf "%s\n\n", transport
}
' fore.dat
:Transport:000
:Transport:001
:Transport:004
:Transport:003
Explanation:
- Call
awk
- Treat ':' as the field separator.
- For any lines starting with ':Transport:', store that entire line as
transport
. - For any lines with three fields where the second is "Server" and the third is "APBS", print the last stored value of
transport
followed by a pair of newlines. - use
fore.dat
as the input file.
There are a number of different ways you could do this. This is just one.
You need to give a little more detail about what language you are working with.
Here is what I would do. I would scan each line of the file. I would put the 'last read' line into a buffer. If the next line contains what you are looking for, output the line that is stored in the buffer.
grep -B1 APBS <filename>
returns the line containing APBS and the line just above it.
grep -B1 APBS <filename>| grep Transport
would return lines with Transport numbers.
Before reading a line (actual_line), store the line you have in a temp variable (previous_line). When you find the one you need (actual_line is the one you look for), just return the previous one (previous_line)
Given that you are not using GNU grep
and assuming you cannot get it installed, then you have to fall back on other tools. This is a script I called 'sgrep' which, as you can see from the date information, is fairly old but was written for Xenix, SunOS (pre-dates Solaris), HP-UX, AIX and a legion of other long-gone variants of Unix. It does the job fairly thoroughly - it is more comprehensive than you currently need.
: "$Id: sgrep.sh,v 1.3 1989/05/12 10:24:14 john 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:n" "$@"`
case $# in
0) echo "Usage: $0 [-n] [-f x] [-b y] pattern [files]" >&2
exit 1;;
esac
number="'s/^\\([0-9][0-9]*\\) /\\1:/'"
filename="'s%^%%'" # No-op for sed
f=3
b=3
nflag=no
while [ $# -gt 0 ]
do
case $1 in
-f) f=$2; shift 2;;
-b) b=$2; shift 2;;
-n) nflag=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
for file in $*
do
{
ed - $file <<-!
g/$pattern/.-${b},.+${f}n
!
} |
eval sed -e "$number" -e "$filename" \| $sort |
case $nflag in
yes) cat -;;
no) sed 's/[0-9][0-9]*://';;
esac
done
rm -f $tmp
trap 0
exit 0
I had to dig it out of the fossil-beds where I keep ancient software. I have a Perl script that does basically the same job; I don't use either very often since I normally have GNU grep installed.
精彩评论