UNIX beginner

laserpp

Distinguished
Nov 29, 2008
137
0
18,630
Hi, I am taking my first UNIX class in school and I am very confused on my 3rd script I have to write. I am hoping some of you can help me. Well what I have to do is write a script that when I execute it is takes the largest number. For example say I write a script called largest, I then execute it ./largest 50 100 90 5, it should tell me the largest number in the set. So it should say "The largest number is 100." You should be able to enter up to 9 numbers. Okay well this is what I have and I don't know why it isn't working.

count=$#
args=("$@")
max=$1

while [ $count -gt 0 ]
do
num=${args[count]}
if test num -gt max
then
let max=num
let count=count-1
fi

done
echo "The largest number is $max"
echo "Done"
exit 0


what I am trying to do is set the first number entered into max then go through the array each time assigning the value to num, then I want to test the value in num to see if its greater then max and if it is then that value will take over the max value. For example say I enter ./largest 50 10 6 90. max will be set at 50 then num would be set to whatever is in array 4 which would be 90. Then is will see if num(90) is greater then max(50) and since it is max will become 90. then it will go down the list so num will become the next array which is 6 and do the same test and since 6 isnt greater than 50 max will remain as 50. So it will do this for all the numbers and the largest number will be in max. Then "echo "The largest number is $max"" will print out the largest number. Seems like it should work but it keeps saying "./sum line 8: test: num: integer expression expected" no clue what to do. Please help.vi
 

Ijack

Distinguished
You've got the basic idea, but you've made a few trivial mistakes.

1. You've decremented count inside the test. Initially $max and $num are going to be the value of the last member of the array. The test is always going to fail, count will never get decremented, so you have an infinite loop.

2. You've got a number of variable references where $ is missing. Remember, to extract the value of the variable you need to preceed it with $. For example, first time you access the args array you have args[count]; this should be args[$count].

3. You're treating the array as if it were args[1], args[2], .... But arrays start from 0, so it should be args[0], args[1], .... There's a couple of ways you could correct this - replacing args[$count] with args[$count - 1] is probably the easiest.

1. was just a moments lapse, 2. & 3. are very common mistakes when beginning shell scripting. I'm not going to reproduce a correct program here as I'm sure that you are bright enough to correct it, and you'll learn more that way.
 

laserpp

Distinguished
Nov 29, 2008
137
0
18,630
Thanks a lot, I will trying to correct this, I did try putting $ in front of the variables but still didn't work so I just ignored it but never put the count-1 outside the loop. I am great in my C++ classes but UNIX owns me and my teacher is a retard, showed her my script and she never pointed out any of the things you said.
 

Ijack

Distinguished
I must confess that I didn't immediately spot any of the errors, although if I'd thought about it I would have, execpt the misplacement of the count = $count - 1 statement.

So I did what you should always do - inserted a few judicious "echo" statements to see what was happening to the variables. It was then fairly obvious what was wrong.
 

Zenthar

Distinguished
Dec 31, 2007
250
0
18,960
I'd like to add a few comments over what others have said.

First, you can use the [ code ] [ / code ] brackets in the forum to keep indentation (example lower).

Second, if using bash, you can use some sort of "foreach" loop where the field seperator in stored in the IFS variable (default is space I think). Example:
Code:
#!/bin/bash
for ARG in "$@"
do
   echo "ARG: $ARG"
done

Third, the brackets ([ ]) can be used instead of "test", you used it in your while statement, but not in your if statement, I don't know if you did it on purpose.
 

laserpp

Distinguished
Nov 29, 2008
137
0
18,630
Ok redid the code, added the $ to all variables, for the let count = count-1 should it be let $count=$count-1 because when I did that it gave an error? it works when the largest number is entered first but when its not it gives me an error:

./sum 10 30 12

./sum: line 9: let: 10=12: attempted assignment to non-variable (error token is "=12")

./sum: line 9: let: 10=30: attempted assignment to non-variable (error token is "=30")

The largest number is 10
Done


Do I have to declare num somewhere. that is what the error seems to be saying? I am so confused with UNIX way of declaring variables. Seems like You can put them anywhere and they are declared unlike C++.


Code:
count=$#
args=("$@")
max=$1
while [ $count -gt 0 ]
do
        num=${args[$count - 1]}
        if [ $num -gt $max ]
        then
        let $max=$num
        fi
        let count=count-1


done
echo "The largest number is $max"
echo "Done"
exit 0

I was also confused on why count=count-1 had to be outside the loop but now I see that this is a nested loop and the count-1 is still in the while loop where it should of been.
 

Zenthar

Distinguished
Dec 31, 2007
250
0
18,960
With "let", I think you don't need the $ sign, that is why it's giving you an error.

As for not needing explicit declaration, you are right, in most Linux/Unix shell (BASH/KSH/...) you don't declare variable, you just start using them. This can be very confusing and error-prone so you need to be careful.

Instead of using "let", in BASH you can also use $(( )) like this: count=$(( count - 1 )). If you want more information, you can check here.
 

Ijack

Distinguished
No $ on the left-hand side (because you're not extracting the value of the variable). So
Code:
let max = $num
let count = $count -1
etc. But you need it in the comparisons, becasue there you are extracting the value of each variable:
Code:
if [$num -gt $max]
etc.
 

laserpp

Distinguished
Nov 29, 2008
137
0
18,630
WooHoo it works thanks a lot guys. God I like c++ so much better. UNIX is so confusing. Ok so when using let the variable on the left never uses $ but the one on the right does.
 

Ijack

Distinguished
It seems illogical, but it's not really. When you are working with variables you are concerned with two things.

A container (the variable)
Something in the container (the value of the variable)

In UNIX shell scripts you refer to a variable by a name, say foo, and it's contents as $foo. So the "$" extracts the value from the variable. So in an assigment you want to take the contents of one container and store it in another. Hence:
Code:
let variable1 = $variable2
Most programming lanuguages hide this from you, although C and C++ let you see the gory details in the form of pointers (which beginners can find equally confusing).
 

Zenthar

Distinguished
Dec 31, 2007
250
0
18,960
BTW, I'd like to point-out that BASH is not a programming language, it's a scripting language (a very powerful one, but still). To compare BASH to C++ is as fair as comparing DOS batch syntax to C++. BASH script are executed by the same shell you use when in CLI mode.