1

So I have the following bash script, which is supposed to read a .txt file of an n amount of integers, add it to an array, sort the array using selection sort, then print the array:

a=()
filename="$1"
while IFS='' read -r line || [[ -n "$line" ]]; do
    a+=($line)
done < "$filename"

for((i=0; i<${#a[@]}; i++))
do
  min=$i
  for((j=$i+1; j<${#a[@]}; j++))
  do
    if (( ${a[$j]} <= ${a[$min]} ))
    then
      $min=$j
      echo "$min"
    fi
  done
  temp=a[$i]
  a[$i]=a[$min]
  a[$min]=$temp
done

for i in ${a[@]}
do
  echo $i
done

The problem is that the conditional within the inner loop throws an exception, where the problem I believe is that the array elements are all strings, and I'm not sure how to cast them to strings in this situation. Also, I don't think I'm swapping the two values properly. The output:

sh selectionsort.sh 10.txt
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 152ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 436ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 756ax error: invalid arithmetic operator (error token is "
 ") 391ax error: invalid arithmetic operator (error token is "
 ") 391ax error: invalid arithmetic operator (error token is "
 ") 391ax error: invalid arithmetic operator (error token is "
 ") 391ax error: invalid arithmetic operator (error token is "
 ") 391ax error: invalid arithmetic operator (error token is "
 ") 391ax error: invalid arithmetic operator (error token is "
 ") 435ax error: invalid arithmetic operator (error token is "
 ") 435ax error: invalid arithmetic operator (error token is "
 ") 435ax error: invalid arithmetic operator (error token is "
 ") 435ax error: invalid arithmetic operator (error token is "
 ") 435ax error: invalid arithmetic operator (error token is "
 ") 404ax error: invalid arithmetic operator (error token is "
 ") 404ax error: invalid arithmetic operator (error token is "
 ") 404ax error: invalid arithmetic operator (error token is "
 ") 404ax error: invalid arithmetic operator (error token is "
 ") 853ax error: invalid arithmetic operator (error token is "
 ") 853ax error: invalid arithmetic operator (error token is "
 ") 853ax error: invalid arithmetic operator (error token is "
 ") 278ax error: invalid arithmetic operator (error token is "
 ") 278ax error: invalid arithmetic operator (error token is "
 ") 643ax error: invalid arithmetic operator (error token is "
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
a[6]
a[7]
a[8]
a[9]

Any help is appreciated! Note: I know there's easier way to sort arrays, I'm using this script to implement selection sort.

Anthony B
  • 55
  • 6

2 Answers2

1

If you are using bash you can take advantage of its builtin functions like sort and readarray. (notice readarray is available since bash 4+, no OS X support by default.)

You can remove your sorting code and use the following code as described here

readarray -t sorted < <(for b in "${a[@]}"; do echo "$b"; done | sort)

$a will be transformed to a sorted array.

agc
  • 7,973
  • 2
  • 29
  • 50
Mr. bug
  • 366
  • 2
  • 11
  • The point of this script is just to implement the selection sort algorithm using the shell. I know it can be done in an easier method, my only question is what the issue is with the current script. – Anthony B Oct 29 '17 at 01:52
  • I ran it and it worked, the only problem I might figure is `$min=$j` should be `min=$j` – Mr. bug Oct 29 '17 at 02:28
  • Why would you not put the $? I initialized it prior. – Anthony B Oct 29 '17 at 02:40
  • In my bash version it failed with `./test.sh: line 15: 2=3: command not found`, I was assigning an int to an int – Mr. bug Oct 29 '17 at 02:43
  • The initialization of the for loop? There seems to be no issue there. – Anthony B Oct 29 '17 at 03:10
  • Line 15 is `min=$j`, I ran it on version 4 and 3 of bash and I got the same error `./test: line 15: 3=4: command not found`, `$min=$j` is wrong. it failed with the sequence 1 2 3 5 4 http://tldp.org/LDP/abs/html/varassignment.html – Mr. bug Oct 29 '17 at 03:19
1

$min=$j is definitely an error. It should be min=$j. The way you access the cells of your array (temp=a[$i], a[$i]=a[$min]) too. Use temp=${a[$i]}, a[$i]=${a[$min]}, instead. But there are a few more things that you could improve:

declare -ai a=()
declare -i i j min temp
declare line

filename="$1"
while IFS='' read -r line; do
  [[ $line =~ ^[0-9]+$ ]] && a+=($line) || printf "Warning: not a number (%s)\n" "$line"
done < "$filename"

for (( i=0; i<${#a[@]}; i++ ))
do
  min=$i
  for (( j=i+1; j<${#a[@]}; j++ ))
  do
    if (( a[j] <= a[min] ))
    then
      min=$j
      echo "$min"
    fi
  done
  temp=${a[i]}
  a[i]=${a[min]}
  a[min]=$temp
done

for i in "${a[@]}"
do
  echo "$i"
done

In the context of arithmetic evaluation (((...))) and array indexing (a[...]), variable names are interpreted as their numeric values (no need of $).

I also added variable declarations and a test to eliminate non-integer entries.

Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • Thanks! I'm still confused on why it's not $min =$j. I've declared min prior to this line, don't you always need to put a $ when accessing variables that were already initialized? – Anthony B Oct 29 '17 at 16:01
  • `min` is the variable name.`$min` is its value. – Renaud Pacalet Oct 29 '17 at 16:15
  • And don't we need to change it's value by saying $min rather than min? F.e. a=5, b=1, $a=2, $a=$b is how we change the value of variables, from what I've learned. – Anthony B Oct 29 '17 at 16:41
  • If the value of `min` is 5 and you execute `$min=6` the expansion transforms it into `5=6` and you get an error message because it does not make sense. Think at `$x` as `value(x)` and `x` as the name of the variable. – Renaud Pacalet Oct 29 '17 at 16:59
  • Oh! so $ is similar to the concept of dereferencing a pointer in C, at least that's how I'm understanding it. Thanks! – Anthony B Oct 29 '17 at 19:28