Comparing arrays in bash

Comparing arrays in bash

am 17.01.2008 23:21:56 von rebel

My problem is simple in other languages but I have yet to understand
how to sort and compare values of an array in bash. If I am simply
approaching the problem in the wrong manner please feel free to point
me in the right direction. I know that I could simply create two text
files and sort | diff them but I am trying to learn some new skills,
use of arrays in my bash scripts is one of those skills.

On to the problem.
I need to compare the machines connected to local ports of a server
via a command similar to this...

ssh -R 3333:localhost:22 appserver

Then once connected to the app server I will see something like this
as a result. ps-3333 is the name of the ip address that is connected
in the hosts file. All of the machines making inbound connections to
the server will be in the hosts file.


tcp 0 0 ::ffff:10.180.10.69:22
ps-3333:59149 ESTABLISHED

Using a command like this....

netstat --numeric-ports | grep -i est | grep ps | awk '{print $5}' |
cut -d ":" -f 1


I get the result of ps-3333 which I want to read into the array, which
i believe i can do by enclosing the previous command in () and
assigning the result to an array variable. I would then like to read
the hosts file into a second array which I believe I can do in a
similar manner. At this point I wish to sort and compare the two
arrays and this is where I am lost. Does bash have built in methods
attached to it's arrays in order to allow comparison of strings and
integers? If so I have been unable to find them and would appreciate a
boot in the right direction.

If not I would appreciate some help in the right direction. I am
assuming I would need some sort of method to sort them and then loop
over the two arrays making comparisons. If only diff worked on arrays!


Thanks in advance for any help you provide,

-James

Re: Comparing arrays in bash

am 17.01.2008 23:54:37 von cfajohnson

On 2008-01-17, Rebel wrote:
>
> If only diff worked on arrays!

Given two arrays a and b:

diff <(printf "%s\n" "${a[@]}") <(printf "%s\n" "${b[@]}")


If you need them sorted:

diff <(printf "%s\n" "${a[@]}" | sort ) <(printf "%s\n" "${b[@]}" | sort)


--
Chris F.A. Johnson, author
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence

Re: Comparing arrays in bash

am 18.01.2008 00:18:30 von Harry Putnam

Rebel writes:

> I get the result of ps-3333 which I want to read into the array, which
> i believe i can do by enclosing the previous command in () and
> assigning the result to an array variable. I would then like to read
> the hosts file into a second array which I believe I can do in a
> similar manner. At this point I wish to sort and compare the two
> arrays and this is where I am lost. Does bash have built in methods
> attached to it's arrays in order to allow comparison of strings and
> integers? If so I have been unable to find them and would appreciate a
> boot in the right direction.
>
> If not I would appreciate some help in the right direction. I am
> assuming I would need some sort of method to sort them and then loop
> over the two arrays making comparisons. If only diff worked on arrays!

Not builtin but bash does offer the `=~' regular expression match
operator so you may be able to imagine a way to match them up in for
or while loop.

It didn't come through to me in your message if you will have host
names in both arrays but I guess you expect to have some comparable
part in both so:

for ia in ${array1[@]};do
for ib in ${array[@]};do
if [[ $ia =~ $ib ]];then
echo "Yippee we gotta match with $ia and $ib"
elif [[ ! ( $ia =~ $ib ) ]];then
echo "Ick.. $ia doesn't match $ib"
fi
done
done;

------------>8snip

#!/bin/bash
array1=(one two three four five)
array2=(five four three two one)

for ia in ${array1[@]};do
for ib in ${array2[@]};do
if [[ $ia =~ $ib ]];then
echo "Yippee we gotta match with $ia and $ib"
elif [[ ! ( $ia =~ $ib ) ]];then
echo "Ick.. $ia doesn't match $ib"
fi
done
done;

Re: Comparing arrays in bash

am 18.01.2008 00:20:57 von swordsaintzero

On Jan 17, 4:54 pm, "Chris F.A. Johnson" wrote:
> On 2008-01-17, Rebel wrote:
>
> > If only diff worked on arrays!
>
> Given two arrays a and b:
>
> diff <(printf "%s\n" "${a[@]}") <(printf "%s\n" "${b[@]}")
>
> If you need them sorted:
>
> diff <(printf "%s\n" "${a[@]}" | sort ) <(printf "%s\n" "${b[@]}" | sort)
>
> --
> Chris F.A. Johnson, author
> Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
> ===== My code in this post, if any, assumes the POSIX locale
> ===== and is released under the GNU General Public Licence

I would never have thought of using stdin to take the results and put
them both in diff in this manner, I can't wait to get home to test it
thank you!

Re: Comparing arrays in bash

am 18.01.2008 10:59:52 von Stephane CHAZELAS

On Thu, 17 Jan 2008 17:54:37 -0500, Chris F.A. Johnson wrote:
> On 2008-01-17, Rebel wrote:
>>
>> If only diff worked on arrays!
>
> Given two arrays a and b:
>
> diff <(printf "%s\n" "${a[@]}") <(printf "%s\n" "${b[@]}")
>
>
> If you need them sorted:
>
> diff <(printf "%s\n" "${a[@]}" | sort ) <(printf "%s\n" "${b[@]}" | sort)
[...]

Why using arrays in the first place? A shell is a command
interpreter. Most commands work with streams of lines. So shell
programming is more about handling those streams.

Here you're converting forth and back between stream of lines
and arrays. arrays is a concept that doesn't fit well in shell.

Instead of

# convert from stream to array:
IFS='
'
set -f
a=($(cmd1))

# back to stream:
printf "%s\n" "${a[@]}"

Why not simply:

cmd1

as in:

diff <(cmd1) <(cmd2)

Or if you need to store the output of the commands, you can as
well use scalar variables:

a=$(cmd1)
b=$(cmd2)
diff <(printf '%s\n' "$a") <(printf '%s\n' "$b")

Or temporary files:

cmd1 > /tmp/a
cmd2 > /tmp/b
diff /tmp/a /tmp/b

--
Stephane

Re: Comparing arrays in bash

am 18.01.2008 12:42:01 von cfajohnson

On 2008-01-18, Stephane Chazelas wrote:
> On Thu, 17 Jan 2008 17:54:37 -0500, Chris F.A. Johnson wrote:
>> On 2008-01-17, Rebel wrote:
>>>
>>> If only diff worked on arrays!
>>
>> Given two arrays a and b:
>>
>> diff <(printf "%s\n" "${a[@]}") <(printf "%s\n" "${b[@]}")
>>
>>
>> If you need them sorted:
>>
>> diff <(printf "%s\n" "${a[@]}" | sort ) <(printf "%s\n" "${b[@]}" | sort)
> [...]
>
> Why using arrays in the first place?

Because any decent programming language has them -- for very good
reasons, and because that was what the question was about.

> A shell is a command interpreter.

The shell is also a full and very capable programming language.

> Most commands work with streams of lines. So shell
> programming is more about handling those streams.

Shell programming is about writing programs. Streams are just one
aspect of that.

> Here you're converting forth and back between stream of lines
> and arrays. arrays is a concept that doesn't fit well in shell.

Arrays fit perfectly well in the shell as in any other programming
language.

> Instead of
>
> # convert from stream to array:
> IFS='
> '
> set -f
> a=($(cmd1))
>
> # back to stream:
> printf "%s\n" "${a[@]}"
>
> Why not simply:
>
> cmd1
>
> as in:
>
> diff <(cmd1) <(cmd2)

That's fine -- if that's how the arrays are generated. There was no
indication that it was, and any number of methods could have been
used to generate the arrays.

> Or if you need to store the output of the commands, you can as
> well use scalar variables:
>
> a=$(cmd1)
> b=$(cmd2)
> diff <(printf '%s\n' "$a") <(printf '%s\n' "$b")
>
> Or temporary files:
>
> cmd1 > /tmp/a
> cmd2 > /tmp/b
> diff /tmp/a /tmp/b

As with any programming pangauge, there are many ways to accomplish
any task. Some may be appropriate to the task, while others are
not.


--
Chris F.A. Johnson, author
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence