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

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.

Related

How to use an argument in a loop definition

thanks for your help.
What a I doing wrong, here ? I want the numeric answer to be used in a loop but it does not return what I expected :
if [ "$#" -eq 0 ]; then
echo -n "Enter the number: "
read answer
else
answer=( "$#" )
fi
for i in {1..$answer} ; do echo ${i}; done
When executed, I have this:
me#local misc]$ ./test.sh
Enter the number: 5
{1..5}
I expected the echo to return 1 2 3 4 5
You can also do it like:
if [ "$#" -eq 0 ]; then
echo -n "Enter the number: "
read answer
else
answer=( "$#" )
fi
for i in $(seq 1 $answer) ; do echo ${i}; done
With no proposed answer I decided to switch to bash with that syntax that works (though it bothers me)
for (( i=1 ; i<=${answer} ; i++));

declare in array and print the values randomly from array in bash script

Here is my bash script code
declare -a types=("m4.xlarge" "m5.12xlarge" "m5d.12xlarge" "m4.large" "m4.16xlarge" "t2.2xlarge" "c4.large" "c5.xlarge" "r4.2xlarge" "x1e.4xlarge" "h1.16xlarge" "i3.16xlarge" );
echo "array declared"
for i in {1..100}
do
for (( i=1; i<${arraylength}+1; i++ ))
do
#index=$( jot -r 1 0 $((${#expressions[#]} - 1)) )
randominstancetype=$[$RANDOM % ${#types[#]}];
#randominstancetype=$( shuf -i0-1 -n1 $((${#types[#]} )) );
#randominstancepvtiptype=$[$RANDOM % ${#pvtip[#]}];
#randominstancepubiptype=$[$RANDOM % ${#pubip[#]}];
done
done
I am trying to declare array and then print the elements inside the array randomly for around 100 times. Currently the name of the elements are not getting displayed instead it displays as 3 5 8 etc.. Anyhelp will be appreciated.
$[...] is the old and deprecated version of $((...)). So what you are doing is just simple arithmetic expansion that expands back to the random index.
To access an element of the array with the generated index, use:
echo "${types[$RANDOM%${#types[#]}]}"
Try this snippet:
#!/bin/bash
declare -a types=("m4.xlarge" "m5.12xlarge" "m5d.12xlarge" "m4.large" "m4.16xlarge" "t2.2xlarge" "c4.large" "c5.xlarge" "r4.2xlarge" "x1e.4xlarge" "h1.16xlarge" "i3.16xlarge" )
echo "array declared"
max_random=32767
type_count=${#types[#]}
factor=$(( max_random / type_count ))
for i in {1..1000}
do
random_index=$(( $RANDOM / $factor ))
random_instance_type=${types[$random_index]}
echo $random_instance_type
done
This will print a randomized order of your array types.
for j in {1..100}; do
for i in $(shuf -i 0-$((${#types[*]}-1))); do
printf "%s " "${types[i]}";
done;
printf "\n";
done
If you would allow repetitions, then you can do
for j in {1..100}; do
for i in $(shuf -n ${#types[*]} -r -i 0-$((${#types[*]}-1))); do
printf "%s " "${types[i]}";
done;
printf "\n";
done
The commands make use of shuf and its options :
-n, --head-count=COUNT: output at most COUNT lines
-i, --input-range=LO-HI: treat each number LO through HI as an input line
-r, --repeat: output lines can be repeated
source man shuf

Bubble Sort Shell, no output

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

How to swap array element in bash shell linux?

I have a problem regarding about the syntax on how to swap the element value in an array.
array="5 3 2 1 4"
echo "${array[*]}"
changed=1
while [ $changed != 0 ]
do
changed=0
for (( i=0 ; i<=${#array[#]}-1 ; i++ ))
do
if [ ${array[$i]} -gt ${array[$i+1]} ]
then
tmp=${array[$i]}
array[$i]=${array[$i+1]}
array[$i+1]=$tmp
changed=1
fi
done
done
echo "Sorted array: "
echo "${array[*]}"
Edit:
Thanks for answering my question. I have changed the code, and now and it looks something like this.
But unfortunately there is still a problem.
It says:
jdoodle.sh: line 3: $'\r': command not found
jdoodle.sh: line 8: syntax error near unexpected token `$'\r''
jdoodle.sh: line 8: ` for ((i=0;i<=${#array[#]}-1;i++))
This is one implementation of bubble sort:
#!/bin/bash
array=(5 3 2 1 4)
echo "${array[*]}"
size=${#array[#]}
for (( i=0; i<size-1; i++ )); do
for (( j=0; j<size-i-1; j++ )); do
if (( array[j] > array[j+1] )); then
tmp=${array[j]}
array[j]=${array[j+1]}
array[j+1]=$tmp
fi
done
done
echo "Sorted array:"
echo "${array[*]}"
Major problem with your code is that it actually does not use arrays.
Define arrays like array=(value1 value2 value3). It's also better to use [[ ]] for testing instead of [ ]. If we were to change your code just a little to also create a functioning bubble sort algorithm, it could look like this:
#!/bin/bash
array=(5 3 2 1 4)
echo "${array[*]}"
changed=1 j=0
while [[ $changed != 0 ]]
do
((j++))
changed=0
for (( i=0; i<${#array[#]}-j; i++ ))
do
if [[ ${array[i]} -gt ${array[i+1]} ]]
then
tmp=${array[i]}
array[i]=${array[i+1]}
array[i+1]=$tmp
changed=1
fi
done
done
echo "Sorted array:"
echo "${array[*]}"
I do not get the \r messages, even in your test environment; in general, they are a result of DOS/Windows combatability (with a b).
Since this is obviously a tutorial example (why else would someone do bubblesort), some remarks about the code.
array="5 3 2 1 4"
does not create the array that you want. It creates a string. What you are looking for is:
array=(5 3 2 1 4)
The last element of the array is ${#array[#]}-1. Element counting starts at 0. So your for-loop should be:
for (( i=0 ; i<=${#array[#]}-2 ; i++ ))
-2 because you're referencing ${array[$i+1]}, which would otherwise be outside the boundary.

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

Resources