bash sort array trouble - arrays

My first sort statement works great but for some reason my second sort statement doesn't work and doesn't throw any errors. I can't spot the trouble. Please suggest ways I can make this script better. I know its really messy.
#!/bin/bash
testarr0=(37 32 11 31 41 10)
#target ticket
testarr1=[];
#sort target ticket array
IFS=$'\n' testarr00=($(sort <<<"${testarr0[*]}"))
unset IFS
cou0=0
input="test_tickets0"
while IFS= read -r ticket0
do
IFS=',' read -ra digit0 <<< "$ticket0"
for i in "${digit0[#]}"; do
remv0="${i//]}"
remv1="${remv0//[}"
if [ $cou0 -eq 6 ];then
cou0=0
#sort array
IFS=$'\n' testarr11=($(sort <<<"${testarr1[*]}"))
unset IFS
#compare arrays
echo "${testarr00[#]}"
echo "${testarr11[#]}"
if [[ "[]${testarr00[#]}" == "${testarr11[#]}" ]];then
echo "match"
fi
testarr1=[]
fi
cou0=$((cou0+1))
if [ $cou0 -lt 7 ];then
#push into array
testarr1+=$remv1
fi
done
done < "$input"

Related

storing user values in an array then comparing these variables using bash

while read line
do
if [ $line -ge $zero ]
then
a+=($line) ##here I am attempting to store the values in an array
else
for i in ${a[#]}
do
echo $(a[$i]) ## here I am trying to print them
done
fi
what is going wrong? it is giving this error:
a[1]: command not found
a[2]: command not found
a[3]: command not found
done
From the begining
if [ $line -ge $zero ]
what data type should be in $line?
-ge used in numeric comparison. If $line is a string than use = or if you just wnt to check that it's not empty use this syntax if [[ "$line" ]]
Next.
a+=($line)
Again if $line is a string then you should wrap in "" like this a+=("$line")
coz line can contain spaces.
For loop.
for i in ${a[#]}
do
echo $(a[$i]) ## here I am trying to print them
You'r messing with syntax here for i in ${a[#]} will iterate over arrays values, not indexes. And again if values are strings use "" like this for i in "${a[#]}"
So this echo $(a[$i]) won't work by 2 reasons. First you should use {} here, like this echo ${a[$i]}, second $i is not index, but it's may actualy work if it's a digit but in a wrong way. So here you need just echo $i coz $i is alredy a value from a array. Or rewrite foor loop.
for i in ${!a[#]}
do
echo ${a[$i]} ## here I am trying to print them
done
And last but not least, there is no done at the end of this script or it's just a part? So in the and it should look like this.
while read line; do
if [[ $line ]]; then
a+=( "$line" ) ##here I am attempting to store the values in an array
else
for i in ${!a[#]}; do
echo ${a[$i]} ## here I am trying to print them
done
fi
done < data.txt
echo ${a[#]} # print rusult

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.

Can't empty a bash array (bash --version 3.2.25)

My bash array never empty itself.
I am using bash 3.2.25.
I tried using the folowing methods:
declare -a array
# fill array...
# 1
array=()
# 2
empty_array=()
array=( "${empty_array[#]}" )
# 3
unset array
My array never get emptied, am I doing something wrong?
Full code as requested :
declare -a array
function get_array() {
#active_tills=()
#unset active_tills
#active_tills=( "${active_tills[#]}" )
# fill array
while read -r line || [[ -n "$line" ]]; do
line=$(echo "$line" | cut -d' ' -f1)
if [ -n "$line" ] ; then
to_add+="$line "
fi
done < "$request_tmp"
array=($(echo $to_add))
return 0
}
Then
get_array
for host in "${array[#]}"; do
echo "=> $host"
done
# 1
# 2
# 3
get_array
for host in "${array[#]}"; do
echo "=> $host"
done
# 1
# 2
# 3
# 1
# 2
# 3
to_add is also a global variable, and you don't reset its value before appending to it. However, you don't need it: you can append directly to the array.
declare -a array
function get_array() {
local line rest
array=()
while read -r line rest || [[ -n "$line" ]]; do
if [ -n "$line" ] ; then
array+=("$line")
fi
done < "$request_tmp"
return 0
}
As an aside, if you can guarantee that the input file ends with a newline (as is required of a proper text file in POSIX), you don't need the || [[ -n $line ]] hack in your while loop.

Bash While Loop Variable Mishaps

Before you get concerned, this (hopefully) isn't another of the many threads about having variable access problems from a while loop in BASH. I looked at those and implemented the redirect method, but I'm having some issues.
Code:
#!/bin/bash
rm /tmp/sched.now
rm /tmp/sched.later
NOWURL="schedNOWurl"
LATERURL="schedLATERurl"
curl -s $NOWURL --output /tmp/sched.now
curl -s $LATERURL --output /tmp/sched.later
re='^[0-9]+$'
if grep -q 'no shifts' /tmp/sched.now ; then
nowpeople[0]="No Shifts Assigned For This Time"
nowtime[0]="Now"
else
while read line
do
if [[ ${line:0:1} =~ $re ]] ; then
nowtime[$nowcount]=$line
((nowcount++))
elif [[ ${line:0:1} == '-' ]] ; then
nowpeople[$nowcount]=$line
((nowcount++))
fi
done < /tmp/sched.now
fi
declare -a latertime
declare -a laterpeople
if grep -q 'no shifts' /tmp/sched.later ; then
laterpeople[0]="No Shifts Assigned For This Time"
latertime[0]="Until 23:59"
else
while read line
do
if [[ ${line:0:1} =~ $re ]] ; then
latertime[$latercount]=$line
((latercount++))
elif [[ ${line:0:1} == '-' ]] ; then
laterpeople[$latercount]=$line
((latercount++))
fi
done < /tmp/sched.later
fi
echo ${nowpeople[#]}
echo ${nowtime[#]}
echo ${laterpeople[#]}
echo ${latertime[#]}
The URLs that I'm getting are HTML files. The text I'm attempting to pull in the loops looks something like this
11a-1:30p
- John Doe
with some HTML thrown above and below it. Note that these are all on their own lines.
The issue I'm facing is that the loops aren't saving all of the matches to the array. In the second loop, it should pull three entries into each array. Right now it pulls one with malformed text as follows:
- John Doe
1:30p-4pp
Notice the missing m in pm and the replaced m with a p in pp.
The strange thing is that if I echo $line before the array statement, the line is pulled from the file fine, so it sounds like it's something in the way I'm saving to the array.
Suggestions? Please let me know if you need more details.

Check multiple var if exists in array with grep

I am using this code to check one $var if exists in array :
if echo ${myArr[#]} | grep -qw $myVar; then echo "Var exists on array" fi
How could I combine more than one $vars to my check? Something like grep -qw $var1,$var2; then ... fi
Thank you in Advance.
if echo ${myArr[#]} | grep -qw -e "$myVar" -e "$otherVar"
then
echo "Var exists on array"
fi
From the man-page:
-e PATTERN, --regexp=PATTERN
Use PATTERN as the pattern.
This can be used to specify multiple search patterns, or to protect a pattern beginning with a hyphen (-). (-e is specified by POSIX.)
But if you want to use arrays like this you might as well use the bash built-in associative arrays.
To implement and logic:
myVar1=home1
myVar2=home2
myArr[0]=home1
myArr[1]=home2
if echo ${myArr[#]} | grep -qw -e "$myVar1.*$myVar2" -e "$myVar2.*$myVar1"
then
echo "Var exists on array"
fi
# using associative arrays
declare -A assoc
assoc[home1]=1
assoc[home2]=1
if [[ ${assoc[$myVar1]} && ${assoc[$myVar2]} ]]; then
echo "Var exists on array"
fi
Actually you don't need grep for this, Bash is perfectly capable of doing Extended Regular Expressions itself (Bash 3.0 or later).
pattern="$var1|$var2|$var3"
for element in "${myArr[#]}"
do
if [[ $element =~ $pattern ]]
then
echo "$pattern exists in array"
break
fi
done
Something quadratic, but aware of spaces:
myArr=(aa "bb c" ddd)
has_values(){
for e in "${myArr[#]}" ; do
for f ; do
if [ "$e" = "$f" ]; then return 0 ; fi
done
done
return 1
}
if has_values "ee" "bb c" ; then echo yes ; else echo "no" ; fi
this example will print no because "bb c" != "bb c"

Resources