0

I am using bash to script a basic check. It is in a java environment, and I'm pulling the xmx, xss and xms values from the environment, and then comparing them to a predefined standard. Here is a very simplified version:

xmxstd=1024
xmsstd=512
xssstd=256

xmxval=756
xmsval=512
xssval=128

if [ $xmsstd > $xms_val -o $xssstd > $xss_val -o $xssstd > $xss_val ]; then
    echo "<OFFENDING VALUE>"
fi

I don't know if this is possible in bash or not, but I just want to echo out whatever evaluates to be true in the above statement. Maybe I'm missing something stupid, but i've been all over the place and can't find anything on it and I don't want to end up writing this out in three different if's unless I have to.

  • 1
    Write a function that does one comparison and outputs, and call that function three times. (Pass in additional info like what error should be reported) – Mat May 07 '14 at 13:45
  • that's a pretty good idea and I may utilize it. Once I get this working it will be time to see where I can clean it up anyway! I'm not very good with functions yet though, especially when passing data to them. So I have to build everything to work first, and then go back and deal with cleaning it up and making it more efficient so I can see the results in live time. – NoPathInParticular May 07 '14 at 14:10

4 Answers4

3

The whole contents of the [ ] test is only going to be true or false, there's no way of probing the individual elements without splitting it up again.

You said you didn't want to use if, so how about this:

#!/bin/bash

xmxstd=1024
xmsstd=512
xssstd=256

xmxval=756
xmsval=512
xssval=128

(( xmxstd > xmxval )) && echo "xmx: $xmxval"
(( xmsstd > xmsval )) && echo "xms: $xmsval"
(( xssstd > xssval )) && echo "xss: $xssval"

edit: How about some associative arrays? This will only work on bash version >= 4.0 but I thought I'd give it a go:

#!/bin/bash

declare -A std
declare -A val
std=( [xmx]=1024 [xms]=512 [xss]=256 )
val=( [xmx]=756 [xms]=512 [xss]=128 )

for i in xmx xms xss
do 
    (( std[$i] > val[$i] )) && echo "$i: ${val[$i]}"
done
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • Very nice way to avoid `eval` – William Pursell May 07 '14 at 14:31
  • was using bash 4.1 and tried your associative array solution. It works and is a good, clean solution as well. Since it avoids eval and I now understand why I should avoid eval, I may go with this, so i'm working on putting it into a function to also take into account the comment from Mat which was on my original post. – NoPathInParticular May 08 '14 at 12:46
  • @NoPathInParticular I'm glad you like it :) I guess you could put the inside of the loop into a function call but it's quite short so I'm not sure it's worth it personally. Up to you of course! – Tom Fenech May 08 '14 at 12:54
2

One method:

unset offenders
test $xmsstd -gt $xms_val && offenders+=' xms'
test $xmxstd -gt $xmx_val && offenders+=' xmx'
test $xssstd -gt $xss_val && offenders+=' xss'
echo offenders:$offenders

You could also "simplify" a little:

unset offenders
for v in xms xss xmx; do
        eval test \$${v}std -gt \$${v}_val && offenders+=" $v"
done
echo offenders:$offenders

Simplify is quoted there, because a very good argument can be made that this is complicating things rather than simplifying, and I definitely prefer the first, but if the number of variables grows it doesn't scale well. You can certainly use an array instead of a flat string to keep track of the variables that satisfy the constraint, but that is less portable.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • I marked this one correct because it offered other options as well and had more information for helping me understand the overall issue. However, all of these are correct and the answer I needed. Basically, don't do it like I'm trying! – NoPathInParticular May 07 '14 at 14:06
  • +1 for the "simplified" version! I decided to give the array-based method a go; I added it to my answer in case anyone was interested. – Tom Fenech May 07 '14 at 14:26
1

Combining with -o (all but deprecated, by the way; even the POSIX spec recommends you use separate test commands joined by ||) is for when you don't care which one is true, as long as one is true. However, you do care which one is true, because you want to generate output tied to the true result. You'll have to have separate statements.

xmxstd=1024
xmsstd=512
xssstd=256

xmxval=756
xmsval=512
xssval=128

if [ $xmxstd > $xmxval ]; then
    echo "$xmxstd"
fi
if [ $xmsstd > $xmsval ]; then
    echo "$xmsstd"
fi
if [ $xssstd > $xssval ]; then
    echo "$xssstd"
fi
chepner
  • 497,756
  • 71
  • 530
  • 681
0

If using BASH you can make do:

for k in xms xss xmx; do
   kval="${k}val"
   kstd="${k}std"
   val="${!kval}"
   std="${!kstd}"
   (( std > val )) && echo "offending var: $kval with value: $val"
done
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • What you say is true but you're missing the point of the question. – Tom Fenech May 07 '14 at 13:50
  • Thanks, Yes I misunderstood it initially but I've corrected it now. – anubhava May 07 '14 at 13:56
  • Now you're comparing all three variables against `val` whereas each one should be compared against a separate variable. – Tom Fenech May 07 '14 at 13:58
  • I understand this concept but the "echo "" is what I'm looking for. Can I make it print out only the values which are evaluated as true ? – NoPathInParticular May 07 '14 at 13:59
  • wow you guys are fast. Clearly i'm behind the conversation a bit but I agree with Tom Fenech thus far. – NoPathInParticular May 07 '14 at 14:01
  • @TomFenech: val is not a a single variable, it is iterating 3 variables `$xms_val $xss_val $xmx_val` – anubhava May 07 '14 at 14:07
  • My mistake, I said it the wrong way round. I meant to say that you're only comparing `xmsstd` against three variables, which is different to what the OP was asking for. – Tom Fenech May 07 '14 at 14:10
  • 1
    @anubhava - the accepted answer was accepted for its simplified version and additional information to help me understand. If you look at the simplified version though, it is not comparing only $xmsstd but is comparing each standard var $${v}std with each actual value $${v}_val – NoPathInParticular May 07 '14 at 14:47
  • I have already seen that. I have huge respect for William but am still not convinced on use of `eval`. Google is your friend on why `eval` should be avoided as much as possible. – anubhava May 07 '14 at 15:41
  • I have provided a BASH only version without use of `eval` – anubhava May 07 '14 at 15:50
  • @anubhava I appreciate the information. For future readers, I did some research on this and one of the best articles I found on it was actually on [stackoverflow](http://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead)<-- that's a link! – NoPathInParticular May 08 '14 at 12:39