On Mon, Apr 7, 2025 at 5:37 PM A. James Lewis <ja...@fsck.co.uk> wrote: > > I have always attempted to avoid > using external programs where functionality within bash can meet a > requirement. Doing this allows my scripts to be more reliable, and not > depend on those external tools being installed... > > I have however found it extremely frustrating to open TCP connections > via /dev/tcp, because there appears to be no way to control the > timeout! This means I cannot "try one server and move on to the next > if it's not responding" etc... the default timeout is quite long, so > even a simple script to check a list of servers for a response on a > given port is problematic. > > I realise that the action can be performed in a subshell, with the use > of "timeout", but to my knowledge, a file descriptor cannot be passed > back from that subshell, which makes communicating with a remote system > once the connection is open quite challenging/inconvenient. >
How about doing the entire connection in a function? That would allow using a file descriptor how you want to... even if it means only using it to be quick and check if a server is hanging, if your script is otherwise wanting to do some complex (time consuming) interaction with the server. If you are open to basic external commands like ps and sleep, the below is a way to control the timeout with current bash functionality. #### script begin maxdur=50 # 5 seconds (x0.1) port=80 method=GET path=/ #method=OPTIONS path='*' hosts() { cat <<-EOT www.google.com www.example.com 8.8.8.9 EOT # 8.8.8.8 is Google DNS # I made up the increment } chat() { exec 3<> /dev/tcp/$host/$port cat >&3 <<-EOT $method $path HTTP/1.0 Host: $host Connection: close EOT # use &4 to bypass &1/2 output drop for bash errors cat <&3 | head -n 1 >&4 exec 3<&- } hosts | while read host; do # drop bash errors on eventual timeout chat 4>&1 > /dev/null 2>&1 & dur=0 while ((dur<maxdur)) && ps -p $! > /dev/null; do sleep 0.1 ((dur+=1)) (((dur%10)==0)) && echo "sleeping... waiting on $host" done # kill the connection/chat if it's still trying ps -p $! > /dev/null && kill $! echo "Done with: $host" done #### script end ps. You can put tabs before lines within the heredocs, including the end EOT lines, but the tab character doesn't paste into gmail webmail... :/