开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜