Reputation: 45
Hello all I am trying to bubble sort in shell but I am getting an operand expected error. I have initialized the variables I need to use, and am making sure I am using the correct syntax( correct me if i didn't ). The error I am getting is on this line:
x=${array[$i]}
Thank you
#!/bin/bash
array=( "$@" )
#echo ${array[@]} print all elements in the array
if [ $# -gt 9 ]
then
echo Too many arguments, run the program over again
exit
fi
echo $array
i=0
j=0
#for j in { $j -lt ${#array[@]-1} } #((j = 0; j < $@ - 1}; j++))
while [ $j -lt ${#array[@]-1} ]
do
for i in {$array}
#for((i=0; i< array; i++))
do
x=${array[$i]}
y=${array[$i]+1}
if [ $x -gt $y ]
temp=${array[$i]}
${array[$i]}=${array[$i+1]}
${array[$i+1]}=$temp
fi
done
done
echo "Sorted Array: " ${array[@]}
#if ((array[i] > array[i+1]))
#if((x>y))
#if [ ${array[$i]} -gt ${array[$i]+1} ]
Upvotes: 1
Views: 553
Reputation: 125998
There are a number of places in this script where you've got the syntax off by just enough for it to do something completely different from what you want. To demo the problems, let me initialize a couple of variables:
$ array=(15 22 30 93 27)
$ i=2
Ok, the first problem command is echo $array
. This only prints the first element of the array; to print all of its elements, use echo "${array[@]}"
. Note that I've put double-quotes around it -- double-quotes around variable references are almost always a good idea, to avoid unexpected effects from word splitting and wildcard expansion. And when I say "good idea", I mean "if you don't do this, it'll probably work perfectly fine when you test it, and then sometime later a weird bug will show up and you'll have no idea what's going on until you track the problem down to a variable reference that should've been double-quoted". Double-quoting variable references is just good scripting hygiene. Anyway, here's a quick demo of the incorrect array printing:
$ echo $array # wrong
15
$ echo "${array[@]}" # right
15 22 30 93 27
Second, in while [ $j -lt ${#array[@]-1} ]
, that "-1" is in a place where bash doesn't do math. Generally, inside ${ }
, -something
means that if the variable isn't defined it should use the thing after "-" instead. Here, it basically gets ignored:
$ echo "${#array[@]-1}" # wrong
5
$ echo "${#array[@]}" # equivalent, still wrong
5
In order to do math, you need to get into an arithmetic context. You can do this with $(( ))
:
$ echo "$(( ${#array[@]} - 1 ))" # right
4
... but in this case, it'd be simpler to use an arithmetic test expression (( ))
instead of a plain test with [ ]
. Note that the comparison operators are different between [ ]
and (( ))
, and that you don't have to use $
to get variables' values; it comes out like this:
while (( j < ${#array[@]} - 1 )) # right
Well, except that you don't increment j
in the loop, so it just iterates endlessly. Either add ((j++))
inside the loop, or use a for
loop instead. You have this approach in a comment, but you need to make the same syntax correction there too:
for ((j = 0; j < ${#array[@]} - 1; j++)) # also right
And actually, there's another way to do it; you can use ${!array[@]}
to get a list of the indexes for the array (the "!" makes it give indexes, not contents):
for j in "${!array[@]}" # still right
Next problem: in for i in {$array}
, it just gets the first element of the array, and puts a "{ }" around it:
$ echo "{$array}" # wrong
{15}
This is basically doing the same thing as the outer while
/for
loop, so any of those solutions would work here.
Next, y=${array[$i]+1}
-- again, that's not an arithmetic context, so +
doesn't do what you expect at all. In ${ }
, +something
means "use the value 'something' if the variable is defined". Since array
is defined, this always sets y
to "1". To solve this, just put the +1
inside the [ ]
(which is an arithmetic context, so math works). Also, you can leave off the $
on i
, since it's an arithmetic context and variable references are automatic:
$ echo "${array[$i]+1}" # wrong
1
$ echo "${array[i+1]}" # right
93
Next, for your comparison if [ $x -gt $y ]
, the if
needs a then
(either on the next line or the same line separated by a semicolon:
if [ $x -gt $y ]; then # right
if [ $x -gt $y ]
then # also right
BTW, the if ((array[i] > array[i+1]))
you have in a comment near the end would work fine for getting and comparing the array elements. Provided you use then
with it.
Ok, final problem: in ${array[$i]}=${array[$i+1]}
, you're telling bash to get the value in the i
th element of the array, and set the variable by that name to the value of the next element. Well, sort of, it's actually even weirder than that. Anyway, the thing is that when assigning to an array element, you don't wrap it in ${ }
:
$ ${array[$i]}=${array[$i+1]} # wrong
-bash: 30=93: command not found
$ array[$i]=${array[$i+1]} # right
$ array[i]=${array[i+1]} # also right
Upvotes: 2
Reputation: 15018
for i in {$array}
loops by array elements, so $i
is a string, not an index. To loop by index you want:
for ((i=0; i<${#array[*]}; i++));
do
x=${array[i]}
y=${array[i+1]}
if [ $x -gt $y ]
temp=${array[i]}
${array[i]}=${array[i+1]}
${array[i+1]}=$temp
fi
done
Note that you don't need the $
sign in front of i
.
Furthermore, there are built-in ways to sort; see the answers here, for instance.
Upvotes: 0