If the input file fits comfortably in memory, keep it simple.
If the input file is huge, you can use csplit to break it into pieces at the first foo and at every subsequent bar then assemble the pieces. The pieces are called piece-000000000, piece-000000001, etc. Choose a prefix (here, piece-) that won't clash with other existing files.
csplit -f piece- -n 9 - '%foo%' '/bar/' '{*}' <input-file
(On non-Linux systems, you'll have to use a large number inside the braces, e.g. {999999999}, and pass the -k option. That number is the number of bar pieces.)
You can assemble all the pieces with cat piece-*, but this will give you everything after the first foo. So remove that last piece first. Since the file names produced by csplit don't contain any special characters, you can work them over without taking any special quoting precaution, e.g. with
rm $(echo piece-* | sed 's/.* //')
or equivalently
rm $(ls piece-* | tail -n 1)
Now you can join all the pieces and remove the temporary files:
cat piece-* >output
rm piece-*
If you want to remove the pieces as they are concatenated to save disk space, do it in a loop:
mv piece-000000000 output
for x in piece-?????????; do
cat "$x" >>output; rm "$x"
done
fooand lastbarand print everything in between, if anything. With a stream you would have to read until the firstfoo, and buffer all subsequent lines in memory until EOF, flushing the buffer every time abaris seen. This could mean buffering the entire stream in memory. – jw013 Sep 12 '12 at 14:25