Search code examples
linuxmacosubuntugrepbsd

How do I convert from using `grep -P` to `grep -E`?


I have a script that we use on Ubuntu (Linux) and I'd like to convert it to be used on both Ubuntu (Linux) and MacOS X. grep on Linux is different than grep on FreeBSD (i.e. MacOS X); grep on MacOS X doesn't support the -P option. Unfortunately, using the -E option on both platforms doesn't give the same results. Consider the following code that works on Linux:

wip_scenarios=$(grep -oP "^\d+ scenarios?" log/report.log | grep -oP "\d+")
echo "\n"
echo $wip_scenarios

This returns a 0 on Linux. Replacing all the -P with -E makes this work on MacOS X, but on Linux, this just returns a null which doesn't help the rest of my script when I use conditionals like this:

if [ $wip_scenarios != 0 ];then

One solution is to put a flag at the front and use the appropriate option set depending on the platform, but I was hoping for a cross-platform solution. Is there a way to do this?


Solution

  • For the regex you gave here, this is simple: Change \d to [[:digit:]].

    Thus:

    wip_scenarios=$(grep -Eo '^[[:digit:]]+ scenarios[?]' <report.log | grep -Eo '[[:digit:]]+')
    

    If your script starts with #!/bin/bash (and thus will only ever be run with bash), I'd also consider skipping the dependency on the non-standard extension grep -o, and instead depending on bash itself to separate out the numbers you care about:

    # This works with any POSIX-compliant grep, but requires that the shell be bash
    wip_scenarios_re='([[:digit:]]+) scenarios[?]'
    wip_scenarios_line=$(grep -E '^[[:digit:]]+ scenarios[?]' <report.log)
    [[ $wip_scenarios_line =~ $wip_scenarios_re ]] && {
      wip_scenarios=${BASH_REMATCH[1]}
    }