Bubble Sort Shell, no output - arrays

I'm having a problem where I am trying to use bubble sort in shell, I am not really sure where my problem is occurring as I am assuming that my sorting is correct. I am not getting an error but I am not sorting the numbers at all.
#!/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
j=0
flag=1
a=${#array[#]}
for((j=0;j < $a - 1 && flag==1 ;j++))
do
flag=0
for((i=0; i< $a-j-1; i++))
do
x=${array[$i]}
y=${array[$i+1]}
if ((x>y))
then
flag=1
export temp=$x
export x=$y
export y=$temp
fi
done
done
echo "Sorted Array: " ${array[#]}

As pointed out in the comments, you swap the variables x and y but never any array entries. Instead of
x=${array[$i]}
y=${array[$i+1]}
if ((x>y)); then
flag=1
export temp=$x
export x=$y
export y=$temp
fi
write
x=${array[$i]}
y=${array[$i+1]}
if ((x>y)); then
flag=1
array[$i]="$y"
array[$i+1]="$x"
fi

Related

Fetching data into an array

I have a file like this below:
-bash-4.2$ cat a1.txt
0 10.95.187.87 5444 up 0.333333 primary 0 false 0
1 10.95.187.88 5444 up 0.333333 standby 1 true 0
2 10.95.187.89 5444 up 0.333333 standby 0 false 0
I want to fetch the data from the above file into a 2D array.
Can you please help me with a suitable way to put into an array.
Also post putting we need put a condition to check whether the value in the 4th column is UP or DOWN. If it's UP then OK, if its down then below command needs to be executed.
-bash-4.2$ pcp_attach_node -w -U pcpuser -h localhost -p 9898 0
(The value at the end is getting fetched from the 1st column.
You could try something like that:
while read -r line; do
declare -a array=( $line ) # use IFS
echo "${array[0]}"
echo "${array[1]}" # and so on
if [[ "$array[3]" ]]; then
echo execute command...
fi
done < a1.txt
Or:
while read -r -a array; do
if [[ "$array[3]" ]]; then
echo execute command...
fi
done < a1.txt
This works only if field are space separated (any kind of space).
You could probably mix that with regexp if you need more precise control of the format.
Firstly, I don't think you can have 2D arrays in bash. But you can however store lines into a 1-D array.
Here is a script ,parse1a.sh, to demonstrate emulation of 2D arrays for the type of data you included:
#!/bin/bash
function get_element () {
line=${ARRAY[$1]}
echo $line | awk "{print \$$(($2+1))}" #+1 since awk is one-based
}
function set_element () {
line=${ARRAY[$1]}
declare -a SUBARRAY=($line)
SUBARRAY[$(($2))]=$3
ARRAY[$1]="${SUBARRAY[#]}"
}
ARRAY=()
while IFS='' read -r line || [[ -n "$line" ]]; do
#echo $line
ARRAY+=("$line")
done < "$1"
echo "Full array contents printout:"
printf "%s\n" "${ARRAY[#]}" # Full array contents printout.
for line in "${ARRAY[#]}"; do
#echo $line
if [ "$(echo $line | awk '{print $4}')" == "down" ]; then
echo "Replace this with what to do for down"
else
echo "...and any action for up - if required"
fi
done
echo "Element access of [2,3]:"
echo "get_element 2 3 : "
get_element 2 3
echo "set_element 2 3 left: "
set_element 2 3 left
echo "get_element 2 3 : "
get_element 2 3
echo "Full array contents printout:"
printf "%s\n" "${ARRAY[#]}" # Full array contents printout.
It can be executed by:
./parsea1 a1.txt
Hope this is close to what you are looking for. Note that this code will loose all indenting spaces during manipulation, but a formatted update of the lines could solve that.

Bash: Iterating through an array to get the value at each index

The main goal of this program is to simulate the drawing of a card as many times as the user chooses and then print out a histogram using '*' to represent the number of hits on each card. However, the problem that I am having is retrieving the elements in each array and printing the stars that correlates with them. This is what I have so far:
timelimit=5
echo -e "How many trials would you like to run? \c"
read -t $timelimit trials
if [ ! -z "$trials" ]
then
echo -e "\nWe will now run $trials trials"
else
trials=10
echo -e "\nWe will now run the default amount of trials: $trials"
fi
count=1
MAXCARD=53
declare -a CARDARRAY
while [ "$count" -le $trials ]
do
card=$RANDOM
let "card %= MAXCARD"
let "CARDARRAY[$card] += 1"
let "count += 1"
done
echo ${CARDARRAY[#]}
for (( i=0; i<${#CARDARRAY[#]}; i++));
do
#declare "temp"="${CARDARRAY[$i]}"
#echo "$temp"
#for (( j=0; j<temp; j++));
#do
#echo "*"
#done
echo "$i"
done
Obviously the last for loop is where I'm having trouble and is currently the latest attempt at printing the stars according to how many hits each card has.
You were pretty close. Here's how I'd paraphrase your script:
#!/bin/bash
timelimit=5
printf %s 'How many trials would you like to run? '
read -t $timelimit trials
if [[ ! -z $trials ]] ; then
printf '\nWe will now run %d trials\n' $trials
else
trials=10
printf '\nWe will now run the default amount of trials: %d\n' $trials
fi
count=1
MAXCARD=53
declare -a CARDARRAY
while (( trials-- )) ; do
(( CARDARRAY[RANDOM % MAXCARD] += 1 ))
done
printf '%s\n' "${CARDARRAY[*]}"
for (( i=0 ; i<MAXCARD ; i++ )) ; do
printf %02d: $i
for (( j=0 ; j<${CARDARRAY[i]:-0} ; j++ )) ; do
printf %s '*'
done
printf '\n' ''
done
You can use set -xv to see what bash is running at each step.

read N elements from an array and delete them

I am storing a file list in an array . What I'd like to do is loop through a process that will read N elements of an array and delete all the elements it just read. The Exception is the last iteration , when you come to the last iteration of the loop - whatever remains in the array - just split that out .
th=$1
ar=('f1' 'f2' 'f3' 'f4' 'f5' 'f6')
for ((i=1; i<=$th; i++)); do
<stuff>
if [ "$i" -eq "$th" ]
then
# if its the last iteration of the loop.Whatever remains in the array - spit that out
echo " `echo ${ar[*]}`" >> somefile
# it its anything short of the last iteration.Read N elements of the array at a time
# and then delete them
else
echo " `echo ${ar[*]:0:$N}` " >> somefile
for ((x=0; x<=$N; x++)) ; do
unset ar[$x]
done
fi
The results are very erratic. Even when I use this approach and test if separately
for ((x=0; x<=$N; x++)) ; do
unset ar[$x]
done
It will delete the WHOLE array EXCEPT the $Nth element
I am new to arrays in shell. Any help is gladly appreciated
Try the following:
#! /bin/bash
th=3
N=2
ar=('f1 f' 'f2' 'f3' 'f4 x' 'f5' 'f6' 'f7')
for ((i=0; i<$th; i++)); do
if (( $i == $(($th - 1)) )) ; then
echo "${ar[*]}"
else
echo "${ar[*]:0:$N}"
ar=( "${ar[#]:$N}" )
fi
done
Output:
f1 f f2
f3 f4 x
f5 f6 f7
Note:
Arrays in bash are zero based.
Indices are not adjusted after unset ar[$x], therefore it would be easier to reconstruct the array as ar=( "${ar[#]:$N}" ) to force new indices to start at zero..
Update:
Or you could avoid the reconstruction of the array using:
#! /bin/bash
th=3
N=2
ar=('f1 f' 'f2' 'f3' 'f4 x' 'f5' 'f6' 'f7')
for ((i=0; i<$th; i++)); do
if (( $i == $(($th - 1)) )) ; then
echo "${ar[*]:$(($i * $N))}"
else
echo "${ar[*]:$(($i * $N)):$N}"
fi
done

Array Values Refer To Variables

I'm trying to write a script in bash that "builds" an array from seven variables. For example:
a=7
b=3
c=5
....
declare -a elem_arr=( "$a" "$b" "$c"..."$g" )
echo "$elem_arr[1]" # this doesn't echo anything.
if [ "$elem_arr[1]" -ne "$elem_arr[2] ]; then
echo "$elem_arr[1] is not equal to $elem_arr[2]"
fi
This doesn't seem to work. Is it possible to construct an array in such manner?
Check this out
#! /bin/bash
a="This"
b="script"
c="works!"
count=1
for i in $( echo $a $b $c )
do
array[$count]=$i
count=$[ $count+1 ]
done
echo "${array[1]} ${array[2]} ${array[3]}"
This script works by using a for loop to define each element in the array individually. You can then easily call any element using the default syntax ${array[index]}

populate and read an array with a list of filenames

Trivial question.
#!/bin/bash
if test -z "$1"
then
echo "No args!"
exit
fi
for newname in $(cat $1); do
echo $newname
done
I want to replace that echo inside the loop with array population code.
Then, after the loop ends, I want to read the array again and echo the contents.
Thanks.
If the file, as your code shows, has a set of files, each in one line, you can assign the value to the array as follows:
array=(`cat $1`)
After that, to process every element you can do something like:
for i in ${array[#]} ; do echo "file = $i" ; done
declare -a files
while IFS= read -r
do
files+=("$REPLY") # Array append
done < "$1"
echo "${files[*]}" # Print entire array separated by spaces
cat is not needed for this.
#!/bin/bash
files=( )
for f in $(cat $1); do
files[${#files[*]}]=$f
done
for f in ${files[#]}; do
echo "file = $f"
done

Resources