Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
610 views
in Technique[技术] by (71.8m points)

awk - Grep Access Multiple lines, find all words between two patterns

Need help in scanning text files and find all the words between two patterns. Like say if we have a .sql file, Need to scan and find all words between from' and 'where'. Grep can only scan 1 line at a time. For this requirement what is the best unix script to use? sed, awk has these features? Pointing to any examples is greatly appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Sed has this:

sed -n -e '/from/,/where/ p' file.sql

Prints all the lines between a line with a from and a line with a where.

For something that can include lines that have both from and where:

#!/bin/sed -nf

/from.*where/ {
    s/.*(from.*where).*/1/p
    d
}
/from/ {
    : next
    N
    /where/ {
        s/^[^
]*(from.*where)[^
]*/1/p
        d
    }
    $! b next
}

This (written as a sed script) is slightly more complex, and I'll try to explain the details.

The first line is executed on a line that contains both a from and a where. If a line matches that pattern, two commands are executed. We use the s substitute command to extract only the parts between from and where (including the from and where). The p suffix in that command prints the line. The delete command clears the pattern space (the working buffer), loading the next line and restarting the script.

The second command starts to execute a series of commands (grouped by the braces) when a line containing from is found. Basically, the commands form a loop that will keep appending lines from the input into the pattern space until a line with a where is found or until we reach the last line.

The : "command" creates a label, a marker in the script that allows us to "jump" back when we want to. The N command reads a line from the input, and appends it to the pattern space (separating the lines with a newline character).

When a where is found, we can print out the contents of the pattern space, but first we have to clean it with the substitute command. It is analogous to the one used previously, but we now replace the leading and trailing .* with [^ ]*, which tells sed to match only non-newline characters, effectively matching a from in the first line and a where in the last line. The d command then clears the pattern space and restarts the script on the next line.

The b command will jump to a label, in our case, the label next. However, the $! address says it should not be executed on the last line, allowing us to leave the loop. When leaving the loop this way, we haven't found a respective where, so you may not want to print it.

Note however, this has some drawbacks. The following cases won't be handled as expected:

from ... where ... from

from ... from
where

from
where ... where

from
from
where
where

Handling these cases require more code.

Hope this helps =)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...