How to get all strings instances following a custom pattern from a variable to an array in bash?

Viewed 58

The Problem

Using Bash, I have a variable with a string like this one:

STR="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pharetra metus turpis, id rutrum massa auctor.
not ok 1 Chrome 89.0 - [158 ms] - Failed test 1 | Test Name 1
    ---
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pharetra metus turpis, id rutrum massa auctor.
not ok 2 Chrome 89.0 - [158 ms] - Failed test 2 | Test Name 2
    ---
ok 1 Chrome 89.0 - [158 ms] - Passing...
    ---"

And I need to create an array containing only the name of those failing tests. The pattern/rules would be:

  • Lines starting with the 'not ok' phrase.
  • Then, Getting the text after the second dash until the end end-of-line.

What I have tried

So far, I came up the following regexs:

  1. (not ok )(.*?)(\n), that will match the first rule.
  2. (?:[^-]*\-){2}([^-]*), that will match the second rule.

What I am missing

However, I am very lost on how to combine them together to generate the final desire output (an array in bash):

[
'Failed test 1 | Test Name 1',
'Failed test 2 | Test Name 2'
]
2 Answers

You may consider this awk:

awk -F ' - ' '/not ok /{print $3}' <<< "$str"

Failed test 1 | Test Name 1
Failed test 2 | Test Name 2

To create a bash array use:

readarray -t arr < <(awk -F ' - ' '/not ok /{print $3}' <<< "$s")

# check array content
declare -p arr
declare -a arr=([0]="Failed test 1 | Test Name 1" [1]="Failed test 2 | Test Name 2")

Using bash and sed, this one-liner may be what you're looking for:

readarray -t failed_tests < <(sed -n '/^not ok/s/[^-]*-[^-]*- //p' <<< "$STR")

The failed tests will be read into the array failed_tests. You can print them by

printf '%s\n' "${failed_tests[@]}"

Alternatively, in plain bash without using any external utility:

#!/bin/bash

while read -r; do
    [[ $REPLY = 'not ok'* ]] && failed_tests+=("${REPLY#*-*- }")
done <<< "$STR"

printf '%s\n' "${failed_tests[@]}"

Yet another alternative could be to use a grep with Perl regex support:

readarray -t failed_tests < <(grep -Po '^not ok[^-]*-[^-]*- \K.*' <<< "$STR")

If bash version doesn't support readarray, readarray -t failed_tests can be replaced by IFS=$'\n' read -r -d '' -a failed_tests

Related