Problems getting the size of an array in bash - arrays

I have this code to get all the lines filtered by the expression used the grep:
arrvar=( $(grep -Poh '^[A-Z_]+=.+' input.txt) )
arrlen=${#arrvar[#]}
i=0
while : ; do
split=(${arrvar[i]//=/ })
name="${split[0]}"
value="${split[1]}"
echo "index..: $i"
echo "name...: $name"
echo "value..: $value"
i=$(( i + 1 ))
if [ $i > $arrlen ]; then
break
fi
done
Whit this content in input.txt:
HELLO=111
STACK=222
OVERFLOW=333
The result is the following:
index..: 0
name...: STACK
value..: 222
Why only returns the first item of the array instead the three of the file?

You are testing like this:
if [ $i > $arrlen ]
but you probably mean
if (( i > arrlen ))
[ compares lexicographically while (( compares numerical.

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.

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.

How to read first n elements from array

sum=0
read n
read -a array
for i in "${array[#]}"
do
sum=$(( $sum + $i ))
done
echo $sum
I am new in scripting. Here I want to know what can I use to add condition so that reading array will be limited to n times.
Ex:
3
1 2 3 4
here it should add only 1 2 3 and it should not take 4.
I prefer the bash C for loop, it doesn't require conditionals to escape the loop and looks neater.
#! /bin/bash
sum=0
read n
read -a array
for ((x=0; x<n; x++))
do
sum=$(( sum + array[x] ))
done
echo "$sum"
You can avoid the loop altogether and use parameter substitution for slicing the array like this:
$ cat script.bash
sum=0
read -p "Enter n: " n
read -p "Enter space separated array elements: " -a array
echo "${array[#]:0:$n}" | sed 's/\s/+/g' | bc
$ ./script.bash
Enter n: 3
Enter space separated array elements: 1 2 3 4
6
$
echo "${array[#]:0:$n}" | sed 's/\s/+/g' | bc this statement dynamically slices the array and substitutes space \s with + to form the addition expression which is then piped to bc (calculator)
sum=0
i=0
read n
read -a array
while [[ $i -lt $n ]]
do
sum=$(( $sum + ${array[$i]}))
let i++
done
echo $sum
I tried this and it worked. In btw thanks everyone
sum=0
read n
j=0
read -a array
for i in "${array[#]}"
do
if [[ $j -ge $n ]];then
break
else
sum=$(( $sum + $i ))
(( j = j + 1 ))
fi
done
echo $sum
#!/bin/bash
param=$1
sum=0
for i in {0..$param}
do
let " sum = $sum + ${array[$i]} "
done
echo "RESULT: $sum"
and execute
./scipt.sh n

Traverse through an array with missing elements and report those missing elements in shell

Consider the ideal array to be :
0 1 2 3 4 5
Say the array that i get during one execution:
0 1 3 5
My script should display 2 and 4 are missing .
My code so far:
#!/bin/bash
## declare an array variable
a=`cat read/Array/values/from file/`
declare -a simpleArray=( $a )
# get length of an array
arraylength=${#simpleArray[#]}
j=0
while [ $j -lt $arraylength ]
do
# use for loop to read all values and indexes
for ((i=1;i< ${arraylength}+1;i++));
do
y=${simpleArray[$i-1]}
echo $y'current value'
if [ y == j ]
then
echo 'present'
else
echo $j'not present'
j=$((j+1))
fi
done
echo 'for loop close'
done
echo 'while loop close'
EDIT Code
#!/bin/bash
a=`cat /home/muzammilm/textdate.txt`
simpleArray=( 1 2 6 )
j=0;
i=0;
arraylength=${#simpleArray[#]}
echo $arraylength
while [ $j != 6 ]
do
for (( i=0; i< $arraylength; i++ ))
do
if [ ${simpleArray[$i]} = $j ]
then
break
elif [ ${simpleArray[$i]} > $j ]
then
echo $j'not present'
break;
fi
done
j=$((j+1))
done
This gives me an error,though it works perfectly when the ip array contain only two elements
This test is always false:
if [ y == j ]
because it is a string comparison of constant strings "y" and "j". Did you mean
if [ $y = $j ]
instead? (Yes, only one = sign is the correct test for equality).

In array operator in bash

Is there a way to test whether an array contains a specified element?
e.g., something like:
array=(one two three)
if [ "one" in ${array} ]; then
...
fi
A for loop will do the trick.
array=(one two three)
for i in "${array[#]}"; do
if [[ "$i" = "one" ]]; then
...
break
fi
done
Try this:
array=(one two three)
if [[ "${array[*]}" =~ "one" ]]; then
echo "'one' is found"
fi
I got an function 'contains' in my .bashrc-file:
contains ()
{
param=$1;
shift;
for elem in "$#";
do
[[ "$param" = "$elem" ]] && return 0;
done;
return 1
}
It works well with an array:
contains on $array && echo hit || echo miss
miss
contains one $array && echo hit || echo miss
hit
contains onex $array && echo hit || echo miss
miss
But doesn't need an array:
contains one four two one zero && echo hit || echo miss
hit
I like using grep for this:
if echo ${array[#]} | grep -qw one; then
# "one" is in the array
...
fi
(Note that both -q and -w are non-standard options to grep: -w tells it to work on whole words only, and -q ("quiet") suppresses all output.)
array="one two three"
if [ $(echo "$array" | grep one | wc -l) -gt 0 ] ;
then echo yes;
fi
If that's ugly, you could hide it away in a function.
if you just want to check whether an element is in array, another approach
case "${array[#]/one/}" in
"${array[#]}" ) echo "not in there";;
*) echo "found ";;
esac
In_array() {
local NEEDLE="$1"
local ELEMENT
shift
for ELEMENT; do
if [ "$ELEMENT" == "$NEEDLE" ]; then
return 0
fi
done
return 1
}
declare -a ARRAY=( "elem1" "elem2" "elem3" )
if In_array "elem1" "${ARRAY[#]}"; then
...
A nice and elegant version of the above.
in_array() {
local needle=$1 el
shift
for el in "$#"; do
if [ "$el" = "$needle" ]; then
return 0
fi
done
return 1
}
if in_array 1 1 2 3; then
echo true
else
echo false
fi
# alternatively
a=(1 2 3)
if in_array 1 "${a[#]}"; then
...
OPTIONS=('-q','-Q','-s','-S')
find="$(grep "\-q" <<< "${OPTIONS[#]}")"
if [ "$find" = "${OPTIONS[#]}" ];
then
echo "arr contains -q"
fi

Resources