2

I have an array of values coming from bash which i just want to check if there are numbers or not in it. It can contain -, + numbers and spaces at the start or end since bash is evaluating this as sting.

Since every number is represented with , at the end i added (,) to the regex.

Basically i want to check if element is a number or not.

The $val look like these.

[ [ -0.13450142741203308, -0.3073260486125946, -0.15199440717697144, -0.06535257399082184, 0.02075939252972603, 0.03708624839782715, 0.04876817390322685 ] ,[ 0.10357733070850372, 0.048686813563108444, -0.1413831114768982, -0.11497996747493744, -0.08910851925611496, -0.04536910727620125, 0.06921301782131195, 0.02547631226480007 ] ]

This is my code which looks at each value and evaluates each. However it doesn't seem to catch the cases.

re='^[[:space:]][+-]?[0-9]+([.][0-9]+)?(,)[[:space:]]$'

for j in ${val[*]}
do
  if ! [[ "$j" =~ $re ]] ; then
   echo "Error: Not a number: $j"
  fi
done

Also it needs to ignore cases which throw [ or ] or ],.

Any ideas how to correct this ? Thanks for the help.

6
  • @WiktorStribiżew ya still doesnt catch. Commented Nov 10, 2021 at 15:53
  • How do you populate $val? Commented Nov 10, 2021 at 16:00
  • not every number ends with a comma. Commented Nov 10, 2021 at 16:21
  • @glennjackman Yes the last one does not end with a , Commented Nov 10, 2021 at 16:22
  • And this one neither: 0.04876817390322685 ] ,[ Commented Nov 10, 2021 at 19:16

2 Answers 2

2

It is likely that $val is coming to you as a string.

If you don't need to validate each number as a fully legit number, you can use shell logic to filter those things that are obviously not numbers:

val='[ [ -0.13450142741203308, -0.3073260486125946, -0.15199440717697144, -0.06535257399082184, 0.02075939252972603, 0.03708624839782715, 0.04876817390322685 ] ,[ 0.10357733070850372, 0.048686813563108444, -0.1413831114768982, -0.11497996747493744, -0.08910851925611496, -0.04536910727620125, 0.06921301782131195, 0.02547631226480007 ] ]'

for e in $val; do  # PURPOSELY no quote to break on spaces
    e="${e/,}"
    case $e in
        ''|*[!0-9.\-]*)  printf "'%s' is bad\n" "$e" ;;
        *) printf "'%s' is good\n" "$e" ;;
    esac
done    

Prints:

'[' is bad
'[' is bad
'-0.13450142741203308' is good
'-0.3073260486125946' is good
'-0.15199440717697144' is good
'-0.06535257399082184' is good
'0.02075939252972603' is good
'0.03708624839782715' is good
'0.04876817390322685' is good
']' is bad
'[' is bad
'0.10357733070850372' is good
'0.048686813563108444' is good
'-0.1413831114768982' is good
'-0.11497996747493744' is good
'-0.08910851925611496' is good
'-0.04536910727620125' is good
'0.06921301782131195' is good
'0.02547631226480007' is good
']' is bad
']' is bad

That is super fast but that will fail on malformed 'numbers' such as 123-456


If you do need to filter out malformed numbers, you can use awk for that:

echo "$val" | awk  -v RS="[^0-9.+-]+" '($0+0==$0)'
# all legit numbers from the string...
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. I adjusted this to fit my script. e="${e/,}" removes the whitespaces ?
No. e="${e/,}" removes the trailing comma for those numbers that have it. It is a form of parameter expansion specifically ${parameter/pattern/string} with string being nul for a deletion.
${e%,} requires a little less extrapolation to envision the predicted result, but they effectively do the same thing. ${e/,} is like saying ${e/,/}. The one difference is that ${e%,} only works at the end. Assuming e=123,456, compare the outputs of $: echo "${e/,} ${e/,/} ${e%,} ${e//,/}", which are 123456, 123456, 123,456 123456.
2

If you populate $val with the given string, it's not an array, it's a string. Using it unquoted would apply word splitting to it which splits it into whitespace separated words. The spaces aren't part of the words, and some of the words (the last one in each bracketed sequence) don't end in a comma:

#! /bin/bash
val='[ [ -0.13450142741203308, -0.3073260486125946, -0.15199440717697144, -0.06535257399082184, 0.02075939252972603, 0.03708624839782715, 0.04876817390322685 ] ,[ 0.10357733070850372, 0.048686813563108444, -0.1413831114768982, -0.11497996747493744, -0.08910851925611496, -0.04536910727620125, 0.06921301782131195, 0.02547631226480007 ] ]'

re='^[+-]?[0-9]+([.][0-9]+)?,?$'

for j in $val ; do
    if ! [[ $j =~ $re ]] ; then
        echo "Error: Not a number: $j"
    fi
done

To use a bash array, declare it with round parentheses and use whitespace to separate the elements:

#! /bin/bash
val=(-0.13450142741203308 -0.3073260486125946 -0.15199440717697144 -0.06535257399082184 0.02075939252972603 0.03708624839782715 0.04876817390322685 0.10357733070850372 0.048686813563108444 -0.1413831114768982 -0.11497996747493744 -0.08910851925611496 -0.04536910727620125 0.06921301782131195 0.02547631226480007)

re='^[+-]?[0-9]+([.][0-9]+)?$'

for j in "${val[@]}" ; do
    if ! [[ $j =~ $re ]] ; then
        echo "Error: Not a number: $j"
    fi
done

4 Comments

Thanks. But the output comes in as [ 0.13, -.145, ] and so on in val and not as ().
Then it's not an array in bash, even if it might be one in Python or whatever else language.
Ya. May be it is evaluating it as a string. But the point is i cant change $val . Also they are , separated except the last.
Are they? 0.04876817390322685 ] ,[. The first snippet works with a string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.