0

How would I parse following output of lein test

$ lein test
lein test nepleaks-engine.core-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

Where I want is get number before failures using bash script.

I only know better is grep,

$ lein test | grep 'failures' | cut -d' ' -f1
0 

Suggest me the better ways of doing this.

7 Answers 7

4

Your solution returns the part of every line that contains "failures" up to the first space character.

If you want to be more specific, you could do:

sed -n '$s/^\([[:digit:]]\{1,\}\) failures.*/\1/p'

That is, only consider the last line ($), and only if it follows a specific pattern: any non-empty sequence of decimal digits followed by  failures (and return that sequence of digits).

3

There is nothing wrong with the way that you are doing it, provided that failures will only occur on one line of the output. Another option might be to anchor on the fact that the number of failures is always on the 4th line of output. This is very easy with awk:

lein test | awk 'NR==4 { print $1 }'

Or to anchor on a line where failures, is the second field:

lein test | awk '$2=="failures," { print $1 }'

Or to anchor on the last line:

lein test | awk 'END { print $1 }'

Or using sed to anchor on the last line:

lein test | sed -n '$ s/^\([0-9]*\).*/\1/p'
1
  • I think lein test | awk '$2=="failures," { print $1 }'is the safest one.
    – prayagupa
    Jun 12, 2014 at 19:11
1

With awk (print $1, means first column):

lein test | grep 'failures' | awk '{print $1}'
2
  • 1
    You don't need the additional grep there. awk '/failures/{print $1}' achieves the same thing. Even better, match the output completely. awk '/^[[:digit:]]+ failures, [[:digit:]]+ errors/{print $1}'
    – Matt
    Jun 12, 2014 at 13:13
  • Thanks. It was just to have an example there was close to his snippets also :-) Jun 12, 2014 at 13:31
1

Try this:

lein test | tail -n 1 | tr -s " " "\n" | head -n 1

How does it work?

  • tail -n 1 takes the last line
  • tr -s " " "\n" replaces all spaces with the new line character. It's a nice trick to tokenize the input by some character.
  • head -n 1 takes the first line
1
  • nice trick. Loved it.
    – prayagupa
    Jun 17, 2014 at 14:13
1

Through awk,

lein test | awk '/ failures,/{print $1}'

And with GNU sed,

lein test | sed -n '/ failures,/s/^\([^ ]\+\).*/\1/p'

Or portably:

lein test | sed -n '/ failures,/s/^\([^ ]\{1,\}\).*/\1/p'
3
  • Note that \+ and \? here are GNU extensions and don't work with all versions of sed. Surely all you want is just * anyway?
    – Graeme
    Jun 12, 2014 at 12:38
  • Then this command will works for all kind of sed's sed -n '/ failures,/s/^\([^ ]\{1,\}\).*/\1/p' Jun 12, 2014 at 12:41
  • Or just s/^\([^ ]*\).*/\1/ is all you need for the replace part in this case.
    – Graeme
    Jun 12, 2014 at 12:45
1

Considering the output, maybe (if you have the GNU implementation of grep):

lein test | grep -m 1 -o '^[[:digit:]]*'

Safer, with the same implementation:

lein test | grep -E 'failures.*errors' | grep -o '^[[:digit:]]*'

From the manpages:

-o, --only-matching

Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.

-m NUM, --max-count=NUM

Stop reading a file after NUM matching lines.[...]

1
  • 1
    That's likely to catch wrong input, considering the real world =)
    – Matt
    Jun 12, 2014 at 13:16
0

You could try using this code:

lein test | tail | tr " " "\n" | head -1

which should give you what you want.

You must log in to answer this question.

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