Arrays in BASH

Arrays are necessary for almost all programming problems, but until today I have not really learnt how to use them in BASH. The particular need this time was to clean up port forwarding entries in the UPnP table of the router, for which I use upnpc.

To delete an UPnP entry, the man page of upnpc gives the following syntax:

Delete port redirection:
       upnpc [options] -d external_port protocol [port2 protocol2] [...]

And to get a list of the current entries, give the "-l" option

upnpc -l
upnpc : miniupnpc library test client. (c) 2006-2010 Thomas Bernard
Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
for more information.
List of UPNP devices found on the network :
 desc: http://192.168.1.1:56688/picsdesc.xml
 st: urn:schemas-upnp-org:device:InternetGatewayDevice:1

Found valid IGD : http://192.168.1.1:56688/upnp/control/WANIPConnection
Local LAN ip address : 192.168.1.4
Connection Type : IP_Routed
Status : Connected, uptime=252838s, LastConnectionError : ERROR_NONE
  Time started : Mon Dec 23 13:30:13 2013
MaxBitRateDown : 100000000 bps   MaxBitRateUp 100000000 bps
ExternalIPAddress = 217.210.110.223
 0 TCP 19827->192.168.1.4:22    'libminiupnpc' ''
 1 TCP 25550->192.168.1.8:25550 'Spotify' ''
 2 UDP 26954->192.168.1.8:26954 'Skype UDP at 192.168.1.8:26954 (2551)' ''
 3 UDP 26955->192.168.1.8:26954 'Skype UDP at 192.168.1.8:26954 (2550)' ''
 4 TCP 43901->192.168.1.4:43901 'Spotify' ''
 5 TCP    22->192.168.1.2:22    'libminiupnpc' ''
 6 TCP    80->192.168.1.2:80    'libminiupnpc' ''
 7 TCP   143->192.168.1.2:143   'libminiupnpc' ''
 8 TCP   993->192.168.1.2:993   'libminiupnpc' ''
 9 UDP 15453->192.168.1.3:15453 'Skype UDP at 192.168.1.3:15453 (2550)' ''
10 TCP 15453->192.168.1.3:15453 'Skype TCP at 192.168.1.3:15453 (2550)' ''
11 TCP 26954->192.168.1.8:26954 'Skype TCP at 192.168.1.8:26954 (2551)' ''
12 TCP 51909->192.168.1.4:51909 'Deluge 1.3.3 at 192.168.1.4:51909' ''
13 UDP 51909->192.168.1.4:51909 'Deluge 1.3.3 at 192.168.1.4:51909' ''
14 TCP 55984->192.168.1.4:55984 'Deluge 1.3.3 at 192.168.1.4:55984' ''
15 UDP 55984->192.168.1.4:55984 'Deluge 1.3.3 at 192.168.1.4:55984' ''
16 TCP 63344->192.168.1.4:63344 'Deluge 1.3.3 at 192.168.1.4:63344' ''
17 UDP 63344->192.168.1.4:63344 'Deluge 1.3.3 at 192.168.1.4:63344' ''
18 TCP 61757->192.168.1.4:61757 'Deluge 1.3.3 at 192.168.1.4:61757' ''
19 UDP 61757->192.168.1.4:61757 'Deluge 1.3.3 at 192.168.1.4:61757' ''
20 TCP 62083->192.168.1.4:62083 'Deluge 1.3.3 at 192.168.1.4:62083' ''
21 UDP 62083->192.168.1.4:62083 'Deluge 1.3.3 at 192.168.1.4:62083' ''
22 TCP 51470->192.168.1.4:51470 'Deluge 1.3.3 at 192.168.1.4:51470' ''
23 UDP 51470->192.168.1.4:51470 'Deluge 1.3.3 at 192.168.1.4:51470' ''
24 TCP 53722->192.168.1.4:53722 'Deluge 1.3.3 at 192.168.1.4:53722' ''
25 UDP 53722->192.168.1.4:53722 'Deluge 1.3.3 at 192.168.1.4:53722' ''
26 TCP 62601->192.168.1.4:62601 'Deluge 1.3.3 at 192.168.1.4:62601' ''
27 UDP 62601->192.168.1.4:62601 'Deluge 1.3.3 at 192.168.1.4:62601' ''
28 TCP 64600->192.168.1.4:64600 'Deluge 1.3.3 at 192.168.1.4:64600' ''
29 UDP 64600->192.168.1.4:64600 'Deluge 1.3.3 at 192.168.1.4:64600' ''
30 TCP 64362->192.168.1.4:64362 'Deluge 1.3.3 at 192.168.1.4:64362' ''
31 UDP 64362->192.168.1.4:64362 'Deluge 1.3.3 at 192.168.1.4:64362' ''
32 TCP 58703->192.168.1.4:58703 'Deluge 1.3.3 at 192.168.1.4:58703' ''
33 UDP 58703->192.168.1.4:58703 'Deluge 1.3.3 at 192.168.1.4:58703' ''
GetGenericPortMappingEntry() returned 713 (SpecifiedArrayIndexInvalid)

The port forwarding entries made by Deluge were obsolete, and I wanted to remove them with a BASH script. Filtering out the Deluge entries was easily done with grep, which gives us the the following table:

upnpc -l | grep Deluge
12 TCP 51909->192.168.1.4:51909 'Deluge 1.3.3 at 192.168.1.4:51909' ''
13 UDP 51909->192.168.1.4:51909 'Deluge 1.3.3 at 192.168.1.4:51909' ''
14 TCP 55984->192.168.1.4:55984 'Deluge 1.3.3 at 192.168.1.4:55984' ''
15 UDP 55984->192.168.1.4:55984 'Deluge 1.3.3 at 192.168.1.4:55984' ''
16 TCP 63344->192.168.1.4:63344 'Deluge 1.3.3 at 192.168.1.4:63344' ''
17 UDP 63344->192.168.1.4:63344 'Deluge 1.3.3 at 192.168.1.4:63344' ''
18 TCP 61757->192.168.1.4:61757 'Deluge 1.3.3 at 192.168.1.4:61757' ''
19 UDP 61757->192.168.1.4:61757 'Deluge 1.3.3 at 192.168.1.4:61757' ''
20 TCP 62083->192.168.1.4:62083 'Deluge 1.3.3 at 192.168.1.4:62083' ''
21 UDP 62083->192.168.1.4:62083 'Deluge 1.3.3 at 192.168.1.4:62083' ''
22 TCP 51470->192.168.1.4:51470 'Deluge 1.3.3 at 192.168.1.4:51470' ''
23 UDP 51470->192.168.1.4:51470 'Deluge 1.3.3 at 192.168.1.4:51470' ''
24 TCP 53722->192.168.1.4:53722 'Deluge 1.3.3 at 192.168.1.4:53722' ''
25 UDP 53722->192.168.1.4:53722 'Deluge 1.3.3 at 192.168.1.4:53722' ''
26 TCP 62601->192.168.1.4:62601 'Deluge 1.3.3 at 192.168.1.4:62601' ''
27 UDP 62601->192.168.1.4:62601 'Deluge 1.3.3 at 192.168.1.4:62601' ''
28 TCP 64600->192.168.1.4:64600 'Deluge 1.3.3 at 192.168.1.4:64600' ''
29 UDP 64600->192.168.1.4:64600 'Deluge 1.3.3 at 192.168.1.4:64600' ''
30 TCP 64362->192.168.1.4:64362 'Deluge 1.3.3 at 192.168.1.4:64362' ''
31 UDP 64362->192.168.1.4:64362 'Deluge 1.3.3 at 192.168.1.4:64362' ''
32 TCP 58703->192.168.1.4:58703 'Deluge 1.3.3 at 192.168.1.4:58703' ''
33 UDP 58703->192.168.1.4:58703 'Deluge 1.3.3 at 192.168.1.4:58703' ''

For each entry to remove, you must give both the port and the protocol, in that order. cut and awk does a god job on each row:

upnpc -l | grep Deluge | cut -d "-" -f 1 | awk '{print $3,$2}'
51909 TCP
51909 UDP
55984 TCP
55984 UDP
63344 TCP
63344 UDP
61757 TCP
61757 UDP
62083 TCP
62083 UDP
51470 TCP
51470 UDP
53722 TCP
53722 UDP
62601 TCP
62601 UDP
64600 TCP
64600 UDP
64362 TCP
64362 UDP
58703 TCP
58703 UDP

Now, store each row as an element in a array, then print each element of that array to one space-delimited string, suitable as input to upnpc -d.

elements=( `upnpc -l | grep Deluge | cut -d "-" -f 1 | awk '{print $3,$2}'` )
my_string=`for i in $(seq 0 $((${#elements[@]} - 1))); do echo -n ${elements[$i]} ""; done`
echo $my_string
51909 TCP 51909 UDP 55984 TCP 55984 UDP 63344 TCP 63344 UDP 61757 TCP 61757 UDP 62083 TCP 62083 UDP 51470 TCP 51470 UDP 53722 TCP 53722 UDP 62601 TCP 62601 UDP 64600 TCP 64600 UDP 64362 TCP 64362 UDP 58703 TCP 58703 UDP

That is about it.

upnpc -d $my_string

So, what about arrays then?

for i in $(seq 0 $((${#elements[@]} - 1))); do echo -n ${elements[$i]} ""; done

References: Advanced Bash-Scripting Guide - Chapter 27. Arrays

comments powered by Disqus


Back to the index

Blog roll

R-bloggers, Debian Weekly
Valid XHTML 1.0 Strict [Valid RSS] Valid CSS! Emacs Muse Last modified: oktober 17, 2019