How to wait for an open port with netcat?
Asked Answered
I

13

99

I'm trying to do a custom dockerfile with jenkins on it. I would to wait until port 8080 is open instead of doing an ugly 'sleep 60' with netcat but I'm not very confident with bash scripts and netcat.

Here is an example of what i'm trying to do:

#!/bin/bash
 
opened=0
 
while [ "$opened"  == "0" ]; do
  echo "Waiting jenkins to launch on 8080..."
  nc -vz localhost 8080
done
 
echo "Jenkins launched"
Indehiscent answered 22/12, 2014 at 9:27 Comment(0)
T
166

You can't set netcat to wait until some port is open, so you have to add part for waiting before next check is made. Try this:

#!/bin/bash

echo "Waiting jenkins to launch on 8080..."

while ! nc -z localhost 8080; do   
  sleep 0.1 # wait for 1/10 of the second before check again
done

echo "Jenkins launched"
Therrien answered 22/12, 2014 at 10:41 Comment(8)
finally I used a curl script to do it: while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do sleep 1 && echo -n .; done;Indehiscent
As a suggestion, you can also decrease the connection timeout in the netcat command to get a more quick response when Jenkins becomes up. It is, nc -G 1 -z localhost 8000.Wiper
nc: invalid option -- 'z'Daltondaltonism
if you use man, you'll see that it is not invalid option: " -z Specifies that nc should just scan for listening daemons, without sending any data to them. It is an error to use this option in conjunction with the -l option. "Therrien
In the repository version of netcat on CentOS 7, the -z option is not there. I think this is true for Fedora as well. I needed to install netcat from source to get the -z option.Provision
This is great! Works well as a one-liner in Alpine Linux: while ! nc -z localhost 8080; do sleep 0.1; doneInsomniac
how do i change this to wait for 2 ports to open ?Tsang
@RarylsonFreitas Do you mind linking there this nc -G option is documented to control timeouts? All netcat documentation I can find mentions -G as having to do with source routing, if the version of netcat supports -G at all.Synge
A
80

I suggest the following one liners:

## netcat version:
timeout 22 sh -c 'until nc -z $0 $1; do sleep 1; done' stackoverflow.com 443

## pure bash version:
timeout 22 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' stackoverflow.com 443

Both commands exit as soon as connection is established, trying every second for up to 22 seconds.

Note that thanks to timeout command exit code is 0 when port is accessible otherwise 124 (if no connection established within given time).

Armandoarmature answered 27/4, 2018 at 4:51 Comment(2)
The pure bash version is great! Can used many scenarios. Thank you!Poore
>> is safer as it does not create a new file or overwrite an existing one.Armandoarmature
K
18

As suggested here, you could also do the following if you don't have nc installed but just bash and coreutils:

#!/bin/bash

echo "Waiting jenkins to launch on 8080..."

while ! timeout 1 bash -c "echo > /dev/tcp/localhost/8080"; do   
  sleep 1
done

echo "Jenkins launched"
Kevinkevina answered 6/2, 2018 at 15:44 Comment(1)
I wonder, did echo > ... ever block? Under which circumstances?Sonorant
E
14

I have found this a common enough problem to write a utility to wait for a port to open, with an optional timeout:

# without timeout
wait-port localhost:8080

# timeout after a minute
wait-port -t 60000 localhost:8080

It's open source and available at github.com/dwmkerr/wait-port. Hopefully others will find it useful!

Eveleen answered 29/5, 2017 at 15:31 Comment(0)
R
11

To expand on user987339's answer, here's how to easily wait for a port in your terminal:

waitport function

Add this function to your ~/.bashrc setup file:

waitport() {
    while ! nc -z localhost $1 ; do sleep 1 ; done
}

Log out then back in to load ~/.bashrc. Then, run this command to verify that port 3000 has a server listening to it:

$ waitport 3000
Connection to localhost port 3000 [tcp/hbci] succeeded!

This has been validated on macOS. It might not work on Fedora/CentOS, as they lack the -z option for netcat.

Rabato answered 24/4, 2018 at 18:41 Comment(0)
T
5

Here is my one-line Bash solution (with netcat) that waits for 10 sec for a TCP connection, and give you feedback whether succeeded or not and while is waiting, and return an exit 0 code if the port is open, otherwise 1:

bash -c 'echo -n "Waiting port 8080 .."; for _ in `seq 1 40`; do echo -n .; sleep 0.25; nc -z localhost 8080 && echo " Open." && exit ; done; echo " Timeout!" >&2; exit 1'

You can replace the hardcoded port 8080 by $1 and remove the bash -c if the snippet is saved in a script file wait-port than then is called within a console with: wait-port 8080.

This is a recording of 3 terminals, two waiting until a port is opened and the other terminals open one of the port, so while one of the wait succeed, the other timed-out:

wait-port test

Although the line has many instructions not one, it may be useful if you need to execute the wait "remotely" in a host where you cannot store the script first, e.g. in a Docker container.

Trustful answered 3/2, 2022 at 16:48 Comment(0)
U
5

I used this to wait for a couple of ports to be open, without netcat:

while (! (: </dev/tcp/localhost/27017) &> /dev/null || ! (: </dev/tcp/localhost/9200) &> /dev/null); do
    sleep 2;
done

Change localhost and the ports as needed.

Untangle answered 4/2, 2022 at 11:5 Comment(0)
S
4

I use this script to check the port before running tests on CI.

#!/bin/bash

for _ in `seq 1 20`; do
    echo -n .
    if nc -z localhost $1; then
        exit 0
    fi
    sleep 0.5
done

exit 1
$ bin/wait-port 3306
Saltpeter answered 1/12, 2021 at 8:42 Comment(0)
C
3

To add onto the excellent answers above, if this is something used very often it may be worthwhile to use tooling for that purpose. I wrote and use uup all the time for this use case.

In your example, the command to run would be:

uup localhost:8080 -r

providing an output like: enter image description here

Coonhound answered 9/10, 2020 at 1:24 Comment(0)
P
3

I have written a utility to wait for a port to open, it can also check MySQL, PostgreSQL, Redis and etc availability.

# Checking TCP port
wait4x tcp localhost:8080

# Checking TCP port with specific timeout (5 Minutes)
wait4x tcp localhost:8080 -t 5m

It's open source and available at https://github.com/atkrad/wait4x. Hopefully others will find it useful!

Perithecium answered 29/1, 2021 at 8:6 Comment(0)
L
3

Here is a for-loop example that has a timeout, so it tries e.g. for 10 times, with exponential backoff (2,4,8,16 seconds etc), but finally gives up. Netcat has also 1 second timeout.

for EXPONENTIAL_BACKOFF in {1..10}; do
    nc -w 1 -z db.local 3306 && break;
    DELAY=$((2**$EXPONENTIAL_BACKOFF))
    echo "db not yet available, sleeping for $DELAY seconds"
    sleep $DELAY
done

The output is:

db not yet available, sleeping for 2 seconds
db not yet available, sleeping for 4 seconds
db not yet available, sleeping for 8 seconds
db not yet available, sleeping for 16 seconds
Leta answered 21/3, 2021 at 11:14 Comment(0)
B
2

For those people who are having trouble with nc: invalid option -- 'z'

I was trying to set this up in a docker image. Surprisingly, there was no option of -z in nc in that image.

Image was - Linux elasticsearch 4.4.0-101-generic #124~14.04.1-Ubuntu SMP Fri Nov 10 19:05:36 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

I used the following loop to wait until the port was opened.

#!/bin/bash

echo "Waiting elastic search to launch on 9200..."

open=0;
while [ $open -eq 0 ]
do
    check_port=`nc -v -w 1 -i 1 127.0.0.1 9200 &> /dev/stdout`
    echo $check_port
    if [[ "$check_port" == *"Connected to"* ]]
    then
        break
    fi
    sleep 1
done

echo "Elastic Search launched"

Following is the one-liner of the above script:

open=0;while [ $open -eq 0 ]; do check_port=`nc -v -w 1 -i 1 127.0.0.1 9200 &> /dev/stdout`; echo $check_port; if [[ "$check_port" == *"Connected to"* ]]; then   break; fi; sleep 1; done
Blinders answered 29/6, 2020 at 10:45 Comment(0)
U
0

I use this sample usage

./xl_wait_port.sh [port] [ up | down ]

Parameters:

  • The port to wait
  • What to wait, the up or down

Which is available for download from github xl_wait_port. I am the author.

Code snippet

echo Waiting for port $PORT_NO to go $MODE.
LOOP_FLAG=1
WARN_FLAG=1
while [ "$LOOP_FLAG" -gt 0 ]; do
  LOOP_FLAG=1
  STATUS=`lsof -i :$PORT_NO`
  if [ "up" == $MODE ]; then
    if [ "1" -eq "$STATUS" ]; then
      LOOP_FLAG=0
    fi
  else
    if [ "0" = "$STATUS" ]; then
      LOOP_FLAG=0
    fi
  fi
  RESULT=$((WARN_FLAG % 35))
  if [ "$RESULT" -eq "0" ]; then
    echo "Process is taking some time. Please check or wait."
  fi
  sleep 1
  ((WARN_FLAG++))
done
echo Port $PORT_NO is now $MODE.
Ullman answered 29/9, 2023 at 22:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.