Use SED to produce a specific format from values in a text file (line by line)

Viewed 93

I have a ports.txt file containing the following data "IP Address, local port, remote port and protocol". This is what the file looks like:

1.1.1.1-22-2222-tcp
2.2.2.2-3000-4321-udp
3.3.3.3-80-8080-tcp
4.4.4.4-443-4443-tcp

What I would like to do is use SED to edit each line by putting the values from the ports.txt file in the correct places.

I've used line 1 from the ports.txt file as an example of the expected outcome:

-A PREROUTING -i eth0 -p tcp -m tcp --dport 2222 -j DNAT --to-destination 1.1.1.1:22

I have worked out that I can read line by line using a loop like this:

while read line; do echo $line; done < ports.txt

but I have no idea how to get SED to extract the values and put them into the required format.

4 Answers

The solution below uses echo, sed, tail and grep to extract the port, protocol and destination.

For the destination: we remove the port & protocol from the end & then substitute the dash (-) for a colon (:). (Also, as a precaution, trailing whitespace is accounted for).

For the protocol: we just remove everything up until the final -, and any trailing whitespace just in case.

For the port: we use grep to find all the numeric sequences, -o giving us just the matching component & then we extract the last such match using tail -1.

: '
INPUT:
1.1.1.1-22-2222-tcp
2.2.2.2-3000-4321-udp
3.3.3.3-80-8080-tcp
4.4.4.4-443-4443-tcp

OUTPUT:
-A PREROUTING -i eth0 -p tcp -m tcp --dport 2222 -j DNAT --to-destination 1.1.1.1:22
-A PREROUTING -i eth0 -p udp -m udp --dport 4321 -j DNAT --to-destination 2.2.2.2:3000
-A PREROUTING -i eth0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 3.3.3.3:80
-A PREROUTING -i eth0 -p tcp -m tcp --dport 4443 -j DNAT --to-destination 4.4.4.4:443
'

while read -r line
do
    dest=$(echo "$line" | sed 's/-[^-]*-[^-]*\s*$//;s/-/:/')
    protocol=$(echo "$line" | sed 's/.*-//;s/\s*$//')
    port=$(echo "$line" | grep -oE '[0-9]+' | tail -1)
    echo "-A PREROUTING -i eth0 -p $protocol -m $protocol --dport $port -j DNAT --to-destination $dest"
done < ports.txt

Use this Perl one-liner:

perl -F'-' -lane 'my ( $ip_address, $local_port, $remote_port, $protocol ) = @F; print "-A PREROUTING -i eth0 -p tcp -m ${protocol} --dport ${remote_port} -j DNAT --to-destination ${ip_address}:${local_port}";' ports.txt

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.
-a : Split $_ into array @F on whitespace or on the regex specified in -F option.
-F'-' : Split into @F on dash (-), rather than on whitespace.

SEE ALSO:
perldoc perlrun: how to execute the Perl interpreter: command line switches

Using sed:

sed -rn 's/(^.*)-(.*)-(.*)-(.*$)/A PREROUTING -i eth0 -p \4 -m \4 --dport \3 -j DNAT --to-destination \1:\2/p' ports.txt

Split the lines into individual sections split with - and substitute the lines for the different sections (designated with \n) printed in the format required.

Using awk, set the field delimiter to - and then print using the fields, in the format required.

awk -F- '{ print "A PREROUTING -i eth0 -p "$4" -m "$4" --dport "$3" -j DNAT --to-destination "$1":"$2 }' ports.txt
Related