Bash is one of these gems in the computer world that do not require reading manual for most of the basic use. But extensive reading can lead to expertise and such people tend to prefer bash for tasks of increasing complexity whereas others would have already turned to higher level programming languages.
One such case is networking. How many people know that you can do basic socket I/O with bash? One of such people is my coworker, who pointed this out for me.
Pseudo device for network I/O
If you take input from or redirect output to specially crafted non-existant device node, bash opens connection to specified host and transmits the data over network. Bash manual explains:
/dev/tcp/host/portIf host is a valid hostname or Internet address, and port is an integer port number or servicename, bash attempts to open a TCP connection to the corresponding socket./dev/udp/host/portIf host is a valid hostname or Internet address, and port is an integer port number or servicename, bash attempts to open a UDP connection to the corresponding socket.
Simple use case: netcat
The most basic usage would be in a situation where you need to use netcat, but you do not have it nor have you permission to install it. But you do have bash. So to get input from other host:
user@host1> cat < /dev/tcp/host2.example.com/1234 This is input from host2
Or to output to other host, simply
user@host1> echo "Output this" > /dev/tcp/host2.example.com/1234
Advanced use case: full I/O to HTTP server
There might be situations where a bash script would benefit from ability to communicate with a full-blown HTTP server e.g. to receive input to be parsed or post it’s results to a webpage. Though, talking to HTTP server requires two-way channel between peers and both input and output to that channel, which is a bit tricky in bash, but nonetheless achievable.
This example shows how to GET a file list from HTTP server
#!/bin/bash SERVER="host2.example.com" PORT="80" PATH="/filelist.txt" # Set up filedescriptor so that it can be read and written to # Note: the number can be anything, as long as it is not in use already # which means this should be greater than 2 exec 3<>/dev/tcp/$SERVER/$PORT # Submit query echo "GET $PATH HTTP/1.1 host: $SERVER " >&3 # Parse the result while read line <&3 do # output to stdout echo $line >&1 done # close the input exec 3<&- # close the output exec 3>&-
I leave it to the reader to implement header parsing to output only HTTP body and to handle persistent connections correctly (i.e. read Content-Length header and act upon it). Above script would wait until the server closes the connection on timeout or the user terminates the script.
Though one might argue that what is the use of all this when we do have other programming languages with full support of HTTP and no need to parse it all ourselves. Still occasions might arise where we do not have one or the other required library available or existing code is written in bash and porting it to other language just for simple networking seems unreasonable.