Print specific lines that have two or more occurrences of a particular character

Viewed 110

I have file with some text lines. I need to print lines 3-7 and 11 if it has two "b". I did

sed -n '/b\{2,\}/p' file but it printed lines where "b" occurs two times in a row

2 Answers

You can use

sed -n '3,7{/b[^b]*b/p};11{/b[^b]*b/p}' file
## that is equal to 
sed -n '3,7{/b[^b]*b/p};11{//p}' file

Note that b[^b]*b matches b, then any zero or more chars other than b and then a b. The //p in the second part matches the most recent pattern , i.e. it matches the same b[^b]*b regex.

Note you might also use b.*b regex if you want, but the bracket expressions tend to word faster.

See an online demo, tested with sed (GNU sed) 4.7:

s='11bb1
b222b
b  n    b
ww
ee
bb
rrr
fff
999
10
11 b nnnn bb
www12'
sed -ne '3,7{/b[^b]*b/p};11{/b[^b]*b/p}' <<< "$s"

Output:

b  n    b
bb
11 b nnnn bb

Only lines 3, 6 and 11 are returned.

Just use awk for simplicity, clarity, portability, maintainability, etc. Using any awk in any shell on every Unix box:

awk '( (3<=NR && NR<=7) || (NR==11) ) && ( gsub(/b/,"&") >= 2 )' file

Notice how if you need to change a range, add a range, add other line numbers, change how many bs there are, add other chars and/or strings to match, add some completely different condition, etc. it's all absolutely clear and trivial.

For example, want to print the line if there's exactly either 13 or 27 bs instead of 2 or more:?

awk '( (3<=NR && NR<=7) || (NR==11) ) && ( gsub(/b/,"&") ~ /^(13|27)$/ )' file

Want to print the line if the line number is between 23 and 59 but isn't 34?

awk '( 23<=NR && NR<=59 && NR!=34 ) && ( gsub(/b/,"&") >= 2 )' file

Try making similar changes to a sed script. I'm not saying you can't force it to happen, but it's not nearly as trivial, clear, portable, etc. as it is using awk.

Related