LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-11-2005, 11:27 AM   #1
linuxLuser
Member
 
Registered: Jan 2005
Distribution: Gentoo
Posts: 111

Rep: Reputation: 16
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
 
Old 08-11-2005, 11:41 AM   #2
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
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
 
Old 08-11-2005, 11:50 AM   #3
linuxLuser
Member
 
Registered: Jan 2005
Distribution: Gentoo
Posts: 111

Original Poster
Rep: Reputation: 16
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
 
Old 08-11-2005, 11:57 AM   #4
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
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 $?
}

Last edited by keefaz; 08-11-2005 at 12:02 PM.
 
1 members found this post helpful.
Old 09-10-2008, 05:36 PM   #5
iPenguin
LQ Newbie
 
Registered: Sep 2008
Posts: 12

Rep: Reputation: 2
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...
 
Old 09-11-2008, 01:26 PM   #6
jan61
Member
 
Registered: Jun 2008
Posts: 235

Rep: Reputation: 47
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

Last edited by jan61; 09-11-2008 at 02:52 PM. Reason: forgot a sed option, pattern was silly
 
Old 06-04-2010, 06:59 AM   #7
rudeboy75
LQ Newbie
 
Registered: Nov 2008
Posts: 3

Rep: Reputation: 0
how about
Code:
if ! [ "$1" -eq "$1" 2> /dev/null ]
then
  echo "ERROR: not a number!" > /dev/stderr
  exit 1
fi
cheers
 
Old 06-04-2010, 07:15 AM   #8
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
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

Last edited by catkin; 06-04-2010 at 07:16 AM. Reason: an->a
 
1 members found this post helpful.
Old 06-05-2010, 09:16 PM   #9
iPenguin
LQ Newbie
 
Registered: Sep 2008
Posts: 12

Rep: Reputation: 2
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
#
 
Old 06-06-2010, 12:08 AM   #10
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
Thanks for sharing

The + is missing after ] in ${arg//[^0-9]/}
 
Old 06-08-2010, 09:54 AM   #11
iPenguin
LQ Newbie
 
Registered: Sep 2008
Posts: 12

Rep: Reputation: 2
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
 
1 members found this post helpful.
Old 11-14-2011, 10:11 AM   #12
kvmreddy
LQ Newbie
 
Registered: Aug 2009
Posts: 15

Rep: Reputation: 3
Arrow

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
 
  


Reply

Tags
bash, number


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Problem displaying Bash array values. shinobi59 Programming 3 01-17-2006 05:45 PM
null values in bash scripts always true? jdupre Programming 5 09-27-2005 05:22 PM
Bash scripting to check text in a website carlp Programming 2 09-20-2005 11:14 AM
bash; reading values from a file km4hr Programming 16 07-28-2005 02:07 PM
bash - comparing a variable to several values davee Programming 3 05-05-2003 07:26 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:27 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration