Bash has a nifty feature to open tcp and udp connections and read/write data to that connection. The Advanced Bash Scripting Guide and the bash man page offers some information and examples, and google has some odd examples, but all in all there isn’t much variety of information on the internet on the topic. This feature is enabled in Bash at compile time with the flag –enable-net-redirections
It works by assigning a connection to a file descriptor with exec. Protocol must be udp or tcp, hostname must be either an IP or a FQDN. Use any free file-descriptor (3 or higher usually).
1 | exec {file-descriptor}<>/dev/{protocol}/{host}/{port} |
Use &- to close the connection instead of leaving it in the CLOSE_WAIT status.
1 | exec {file-descriptor}<>&- |
Basic Example:
1 2 3 4 5 | exec 5<>/dev/tcp/www.ryanschulze.net/80 echo -e "GET / HTTP/1.1\n\n" >&5 cat <&5 exec 5<&- exec 5>&- |
You may have noticed that the cat will hang around a while after delivering the content. As long as the connection is established it will sit there and wait for data, which can be quite a while depending on the daemon on the other end. If you want to avoid having to wait, kill or ctrl-c the cat you can use read with an input timeout.
1 2 3 4 5 6 7 8 | exec 5<>/dev/tcp/www.ryanschulze.net/80 echo -e "GET / HTTP/1.1\n\n" >&5 while read -t 2 line do echo $line done <&5 exec 5<&- exec 5>&- |
In the example if read has to wait longer than 2 seconds (-t 2) it will abort reading from the network connection.
If you only want to read a single line you can use head:
1 | head -n1 <&5 |
Although this will have the same timeout problems as cat if there is no more data but the connection is still established, it is useful and quick if you know exactly what kind of result you are expecting.
You don’t have to read the response right away, it will be buffered until you get around to accessing it (even if the other end terminates the connection).