LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   BASH scripting: check for numeric values (https://www.linuxquestions.org/questions/programming-9/bash-scripting-check-for-numeric-values-352226/)

linuxLuser 08-11-2005 12:27 PM

BASH scripting: check for numeric values
 
OK, I didn't know wherelse to ask this one. I have a script that I've made which takes two arguments: a pure number and a filename.

I decided to give it a little bit of flexibility and have it so that it doesn't matter what order those two arguments are put: number then file name, or file name then number. Doesn't matter.

Well, all well and good. But I need to be able to take a word ($1 or $2 in this case) and figure out if it only contains numbers, if not do a
Code:

echo "You complete moron! What'd you take me for!" > /dev/stderr
(or something to that effect).

OK, so my first idea is this (kinda of weird I know):
Code:

if [ $1 = "$(echo $1 | awk '{print strtonum($0)}')" ]; then
  echo "Numeric only value! Good job!"
else
  echo "You fruitcake! Where do you think you get off! Huh?"
fi

The idea is that since the awk function "strtonum()" will return only numeric values, compare what it returns of the argument to what the entire argument is. If they match, then of course they had only typed in numeric values.

Two issues: the awk function strtonum() will believe that the string is a hexidecimal number if proceeded by a 0x. also, if it starts with a 0, then it is interpreted as an octal number. That might be a problem in the unlikely circumstance that somebody would do that. And again, if my little script became so popular that the world over uses it, some Linux newbie in the worlde will burst out in tears as his script just simply doesn't work for some hidden reason only the original programmer (me, in this case) would possibly know about. And as he asks the question over and over again "why? why? why?", the answer shall remain hidden in the way that strtonum() impliments its magic!

Or, in other words: is there a better way? Is there a more common way? Anybody tried this before?

Thanks in advance, ya'll!

-- the dUdemaN davE

keefaz 08-11-2005 12:41 PM

You could test if the value is an integer, with something like :
Code:

function is_integer() {
    printf "%d" $1 > /dev/null 2>&1
    return $?
}

if is_integer $1; then
    echo "$1 is an integer"
else
    echo "$1 is not an integer"
fi


linuxLuser 08-11-2005 12:50 PM

Thanks for the quick response! I'll try 'er out as soon as I can. Your way looks a little bit better. I think it's a better approach: you don't really analyze the text a whole lot. Kinda kool!

-- the dudeeman daVE

keefaz 08-11-2005 12:57 PM

I am not very happy with it though (printf error redirected to /dev/null),
maybe this is better :
Code:

function is_integer() {
    s=$(echo $1 | tr -d 0-9)
    if [ -z "$s" ]; then
        return 0
    else
        return 1
    fi
}

if is_integer $1; then
    echo "$1 is an integer"
else
    echo "$1 is not an integer"
fi

Or even better :
Code:

function is_integer() {
    [ "$1" -eq "$1" ] > /dev/null 2>&1
    return $?
}


iPenguin 09-10-2008 06:36 PM

An idea
 
I use this to separate the text from the numerics in a bash script.

# In this example a file name is one of the expected inputs, a number the other.

Code:

for itm in "$@"
do

  if [ -f "$itm" ]
    then
      afile="$itm"
    else

      cnt=`echo "$itm" | sed -e /\[0-9\]/!d -e /\[\.\,\:\]/d -e /\[a-zA-Z\]/d`

      if [ -z "$cnt" ]
        then
          cnt=0
      fi

  fi

done


# what is accomplished by the script
1. Tests for a file name, sets a variable to that file name.
2. Tests for a number, sets a variable to that number.

The sed line:
- confirms an integer number exists in the text and keeps the text
- drops decimal numbers or text having a period
- drops text having a comma or colon
- drops text having alphas


The $cnt variable is tested for null and assigned the value 0 if null.
I am using integers greater than zero, which is why I set $cnt to zero if no integer numbers were found as a result of the string returned by sed. I test $cnt for zero elsewhere in the rest of my script.

I use the file name and numeric variables elsewhere in a custom script.

Just my 2 cents...

jan61 09-11-2008 02:26 PM

Moin,

try a "negative" check: If there's a non empty input after removing all digits, it's not an integer:
Code:

test -z "$input" -o -n "`echo $input | tr -d '[0-9]'`" && echo NaN
If you want to allow negative values too, you must extend the example (and use another tool like grep / sed):
Code:

echo $input | grep -q '^-\?[0-9]\+$' || echo NaN
Jan

rudeboy75 06-04-2010 07:59 AM

how about
Code:

if ! [ "$1" -eq "$1" 2> /dev/null ]
then
  echo "ERROR: not a number!" > /dev/stderr
  exit 1
fi

cheers

catkin 06-04-2010 08:15 AM

Assuming that "number" is "unsigned integer" then the simplest way to check whether $1 holds a number is
Code:

if [[ $1 =~ ^[0-9]+$ ]]; then
    <whatever is to be done when $1 holds a number>
else
    <whatever is to be done when $1 does not hold a number>
fi


iPenguin 06-05-2010 10:16 PM

I was intrigued by finding a better solution than my lightweight version, and so created a script that runs a series of tests to validate data. The types checked are file, integer decimal, comma delimited integer, comma delimited decimal. After burning through some serious kludge versions, I arrived at some positive results. See what you think.

Code:

#!/bin/sh
#
# fx
#
# A test script to validate input data.
# A variable list is substituted for manual input.
# Note: before running this script try ls > tx for a test file. See below args.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# spaces for output padding
sp='                                                  '

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# try a test sample of arguments to observe the classification results
for arg in 1234 1,222,333,444 12345.00591 1,222,333,444.555789 tx abc 5,00 6,00.007 123abc def456 ',.' ',500' 'a.txt' 127.1.1.1
do

  # try various tests with direct string susbstitution or sed for complex tasks
  #
  # the first 3 tests are for the simple: file, integer, decimal (no comma numbers)
  if [[ -f $arg ]];then
    stat=file
  elif [[ $arg == ${arg//[^0-9]/} ]];then
    stat=integer
  elif [[ `echo $arg | sed '/^[0-9]\{1,24\}\.[0-9]\{1,24\}$/!d'` ]];then
    stat=decimal
  else
    # The more complex comma integer and decimal numbers are handled here.
    # Any other data falls thru as unqualified.
    # ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
    if [[ $arg == ${arg//[^0-9,]/} ]];then

      # proof for comma placement
      if [[ `echo $arg | sed 's/^[0-9]\{1,3\},//;/\([0-9],\)\{1,8\}/!d'` ]];then
        stat=comma_integer
      else
        stat=unqualified
      fi

    elif [[ $arg == ${arg//[^0-9,\.]/} ]];then

      # proof for comma placement
      if [[ `echo $arg | sed 's/^[0-9]\{1,3\},//;s/\(\.[0-9]\{1,24\}\)//;/\([0-9],\)\{1,8\}/!d'` ]];then
        stat=comma_decimal
      else
        stat=unqualified
      fi

    else
      # fallthru for non: file, integer, decimal, int-comma, dec-comma
      stat=unqualified
    fi
    # ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
  fi

  # # # # # # # # # # # # # # # # # # # # # #
  # create a column offset for results
  #
  let "lng=24-${#arg}"
  pad=${sp:0:$lng}

  echo "Status of ( $arg ): $pad $stat"
  # # # # # # # # # # # # # # # # # # # # # #

done
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# EOF
#


catkin 06-06-2010 01:08 AM

Thanks for sharing :)

The + is missing after ] in ${arg//[^0-9]/}

iPenguin 06-08-2010 10:54 AM

Hello, your welcome. Hope the code is interesting/of use.

Actually this is correct: [[ $arg == ${arg//[^0-9]/} ]]

The statement is substituting nothing for any characters that are not 0-9, so that integer numbers only will pass through the substitution unchanged, and this will make the terms equal in characters and test bracket test condition passes; but any non numerics will be substituted out of the right side argument, which makes the bracket test condition fail.

Note that nothing follows the farthest right slash, which is what is substituted.
The double slash indicates to substitute all matching characters specified in the test.

Quick example:
Input: 1500 Test Output: 1500 Input == Output Pass
Input: 8.25 Test Output: 825 Input != Output Fail

Here is a great source for string ops (my fav):
http://tldp.org/LDP/abs/html/refcards.html#AEN21811

kvmreddy 11-14-2011 11:11 AM

You can use different methods to validate integer in bash script.
Check bellow ling for 4 different methods.
How to validate integer in shell script


All times are GMT -5. The time now is 11:26 AM.