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? Jan 19 at 23:29
  • @schrodigerscatcuriosity, no not necessarily 4 digits. Jan 19 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)
    – roaima
    Jan 20 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 Jan 28 at 5:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.