2

Assume that i have a text file containing the following 5 lines:

Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 used: yes , car motor: 1999 , car model: Mercedes , car color: black , year of production: 2012
Thu 20 2022 car model: Kia , car motor: 1500 , car color: red , used: no , year of production: 2010
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010

i'm looking for grep/awk (or other utility that's available on freebsd 11) that will find/print every line where the following condition evaluated TRUE:

Phrase "car motor:" followed by a space and then a numerical value greater than 2000

Such grep/awk is expected to find/print the following lines from the text file:

Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010
2
  • Are the car motor numbers always 4 digits? Commented Jan 19, 2022 at 23:29
  • @schrodigerscatcuriosity, no not necessarily 4 digits. Commented Jan 19, 2022 at 23:40

6 Answers 6

14

I would think that perl would be available on freebsd, and your requirements translate quite directly:

perl -ne 'print if /car motor: (\d+)/ and $1 > 2000' file
10

With GNU awk for the 3rd arg to match():

$ awk 'match($0,/car motor: ([0-9]+)/,a) && (a[1] > 2000)' file
Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010

or with any awk:

$ awk 'match($0,/car motor: [0-9]+/) && (substr($0,RSTART+11) > 2000)' file
Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010

or also with any awk but a bit more cryptically:

$ awk '{k=$0} sub(/.*car motor: /,"",k) && (k > 2000)' file
Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010
3

We need a number of combinations to exclude 2000 itself, which we are treating as a string rather than a numeric value:

grep -E 'car motor: (200[1-9]|20[1-9][0-9]|2[1-9][0-9]{2}|[3-9][0-9]{3}|[1-9][0-9]{4,})' yourfile
1
  • 1
    Trying to optimise REs is usually a great way to make them totally unreadable. They're hard enough as it is (although Perl's x modifier was a great idea when used well) Commented Jan 20, 2022 at 0:14
3

I propose this alternative with grep, using a custom example with variations:

example:

car motor: 1
car motor: 100
car motor: 1000
car motor: 2000
car motor: 2001
car motor: 4000
car motor: 9999
car motor: 10000
car motor: 20001 foo
car motor: 20001
$ grep 'car motor: \([2-9][0-9]\{3,\}\|[0-9]\{5,\}\)' file | grep -v 'car motor: \(2000$\|2000[^0-9]\)'
car motor: 2001
car motor: 4000
car motor: 9999
car motor: 10000
car motor: 20001 foo
car motor: 20001

The pattern [2-9][0-9]\{3,\}\|[0-9]\{5,\} means: select numbers that start within the range of 2-9 followed by 3 digits or more, or the range 0-9 followed by 5 digits or more.

So you cover 2000-9999 and 10000-inf.

Then grep -v 'car motor: \(2000$\|2000[^0-9]\)' to exclude 2000 if it exists.

0
2

Using Raku (formerly known as Perl_6)

raku -ne '.put if m/car \s motor \: \s (\d**4..*)/ && $0 > 2000;' 

OR

raku -ne '.put if .grep(/car \s motor \: \s (\d**4..*)/ && {$0 > 2000});' 

Sample Input (thanks to @schrodigerscatcuriosity):

Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 used: yes , car motor: 1999 , car model: Mercedes , car color: black , year of production: 2012
Thu 20 2022 car model: Kia , car motor: 1500 , car color: red , used: no , year of production: 2010
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010

car motor: 1
car motor: 100
car motor: 1000
car motor: 2000
car motor: 2001
car motor: 4000
car motor: 9999
car motor: 10000

Sample Output (using either code example, above):

Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010
car motor: 2001
car motor: 4000
car motor: 9999
car motor: 10000

It looks as though Raku is available for FreeBSD, provided you follow the advice below to install the Rakudo compiler (from source):

https://rakudo.org/downloads/rakudo/source
https://fluca1978.github.io/2020/01/14/RakuOnFreeBSD.html

It even looks as though a Rakudo-Star binary (Rakudo plus core modules) is/was available for FreeBSD:

https://www.tyil.nl/post/2020/06/21/lately-in-raku/

Briefly,the first example using Raku's m/.../ match operator is almost a direct translation of @glenn_jackman's Perl code. For a less 'backslashy' experience, it could be written:

raku -ne '.put if m[ "car motor: " (\d**4..*) ] && $0 > 2000;'   

The second example uses Raku's grep operator. Sometimes it's nice to return matching lines and make non-matching lines blank. You can do this with grep in Raku like so (numbering all lines as you go):

raku -ne 'put(++$, ". ", .grep: / "car motor: " (\d**4..*)/ && {$0 > 2000} );' 

Sample Output:

1. Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
2. Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
3. 
4. 
5. Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010
6. 
7. 
8. 
9. 
10. 
11. car motor: 2001
12. car motor: 4000
13. car motor: 9999
14. car motor: 10000

https://raku.org

-2
 awk '/car motor: [2-9][0-9]{3,}/' filename

Tue 18 2022 car model: Toyota , car motor: 2001 , car color: blue , year of production: 2018
Thu 19 2022 car model: Mercedes , car color: black , year of production: 2012 , car motor: 4000
Thu 20 2022 price: 150, car model: GMC  , car color: purple , car motor: 3500 , year of production: 2010
1
  • 1
    this will exclude a line with value like 10000 which is >2000 or it will return lines with value ==2000 Commented Jan 28, 2022 at 5:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .