How can I get my external IP address in a shell script?

I need to find my external IP address from a shell script. At the moment I use this function:

myip () {
    lwp-request -o text | awk '{ print $NF }'

But it relies on perl-libwww, perl-html-format, and perl-html-tree being installed.

What other ways can I get my external IP?

Asked By: Eugene Yarmash

 curl -s |cut -d " " -f 5

Replaced site with dutch working one.

Answered By: Maciek Sawicki
wget -O - -q
Answered By: ztank1013
netcat 80 <<< $'GET / HTTP/1.1nHost: icanhazip.comnn' | tail -n1
Answered By: Eugene Yarmash

You can use as alternative to

curl -s

Also has some additional functional. To find out what else information you can receive visit the website.

Answered By: Mr. Deathless

Since and have already been mentioned:

curl -s
Answered By: joschi

If you want to use HTTPS to avoid some potential pitfalls:

_result=$(wget -qO-
_result="${_result##*Your IP address is<br><b>}"
printf '%sn' "${_result%%</b></p>*}"
Answered By: Chris Down

Here is another alternative that depends on hosts who’s business resolves around managing dynamic IP rather that “public service” sites that may go away or change format.

  1. Register your server at one of the many free dynamic dns services (e.g. This will give you a DNS entry like
  2. Install the service’s dynamic update tool (reports IP changes to service).

To get the IP address in a script, just do:

external_ip=`dig +short`

Great for use in cron job to check if dynamic IP has changed and some configuration entries need to be changed.

Answered By: cgmonroe

I prefer to use It’s as simple as:


It’s short and simple to remember.

Answered By: Garrett Fogerlie

Use curl to hit’s ip service

curl -s
Answered By: Chris Montanaro

I’d recommend getting it directly from a DNS server.

Most of the other answers below all involve going over HTTP to a remote server. Some of them required parsing of the output, or relied on the User-Agent header to make the server respond in plain text. Those change quite frequently (go down, change their name, put up ads, might change output format etc.).

  1. The DNS response protocol is standardised (the format will stay compatible).
  2. Historically, DNS services (Akamai, Google Public DNS, OpenDNS, ..) tend to survive much longer and are more stable, more scalable, and generally more looked-after than whatever new hip whatismyip dot-com HTTP service is hot today.
  3. This method is inherently faster (be it only by a few milliseconds!).

Using dig with an OpenDNS resolver:

$ dig +short

Perhaps alias it in your bashrc so it’s easy to remember

alias wanip='dig +short' 
alias wanip4='dig +short -4'
alias wanip6='dig AAAA +short -6'

Responds with a plain ip address:

$ wanip # wanip4, or wanip6 # or, 2606:4700:4700::1111


(Abbreviated from

usage:  dig [@global-dnsserver] [q-type] <hostname> <d-opt> [q-opt]

    q-type   one of (A, ANY, AAAA, TXT, MX, ...). Default: A.

    d-opt    ...
             +[no]short          (Display nothing except short form of answer)

    q-opt    one of:
             -4                  (use IPv4 query transport only)
             -6                  (use IPv6 query transport only)

The ANY query type returns either an AAAA or an A record. To prefer IPv4 or IPv6 connection specifically, use the -4 or -6 options accordingly.

To require the response be an IPv4 address, replace ANY with A; for IPv6, replace it with AAAA. Note that it can only return the address used for the connection. For example, when connecting over IPv6, it cannot return the A address.

Alternative servers

Various DNS providers offer this service, including OpenDNS, Akamai, and Google Public DNS:

# OpenDNS (since 2009)
$ dig +short
$ dig +short

# OpenDNS IPv6
$ dig AAAA +short -6

# Akamai (since 2009)
$ dig ANY +short

# Akamai approximate
# NOTE: This returns only an approximate IP from your block,
# but has the benefit of working with private DNS proxies.
$ dig +short TXT
"ip" ""

# Google (since 2010)
# Supports IPv6 + IPv4, use -4 or -6 to force one.
$ dig TXT +short

Example alias that specifically requests an IPv4 address:

alias wanip4='dig +short -4'

$ wanip4

And for your IPv6 address:

alias wanip6='dig TXT +short -6'

$ wanip6


If the command is not working for some reason, there may be a network problem. Try one of the alternatives above first.

If you suspect a different issue (with the upstream provider, the command-line tool, or something else) then run the command without the +short option to reveal the details of the DNS query. For example:

$ dig

;; Got answer: ->>HEADER<<- opcode: QUERY, status: NOERROR

;      IN  A


;; Query time: 4 msec
Answered By: Timo Tijhof

This always works for me, I use it in my conky to get my IP address.

wget -q -O - | sed -e 's/[^[:digit:]|.]//g'
Answered By: Dai_Trying


















Answered By: Mandar Shinde

Since I don’t rely on the connection or on the service, I use the following code, which tries to get the IP using different services (feel free to add more):

# Get my ip address and put in a file
declare -a arr=("" "" "" "" "")
IP=$(curl -s --retry 3 --retry-delay 10

while [ -z "$IP" ] # If no IP found yet, keep trying!
    sleep 30
    IP=$(curl -s --retry 3 --retry-delay 10 ${arr[$((  RANDOM % ${#arr[@]}  ))]})  

echo -n "$IP" >  /root/clientIP.txt #puts ip address in clientIP.txt
echo "Our address is $IP" 

To add more robustness (e.g. if one of the services changes their format), you could check that $IP is a valid IP using the following function:

# Verify that the parameter passed is an IP Address:
# @Author: Marios Zindilis
# @License: Creative Commons Attribution-ShareAlike 4.0 International License.
# @Date: 2013-05-10
function is_IP() {
if [ `echo $1 | grep -o '.' | wc -l` -ne 3 ]; then
        echo "Parameter '$1' does not look like an IP Address (does not contain 3 dots).";
        exit 1;
elif [ `echo $1 | tr '.' ' ' | wc -w` -ne 4 ]; then
        echo "Parameter '$1' does not look like an IP Address (does not contain 4 octets).";
        exit 1;
        for OCTET in `echo $1 | tr '.' ' '`; do
                if ! [[ $OCTET =~ ^[0-9]+$ ]]; then
                        echo "Parameter '$1' does not look like in IP Address (octet '$OCTET' is not numeric).";
                        exit 1;
                elif [[ $OCTET -lt 0 || $OCTET -gt 255 ]]; then
                        echo "Parameter '$1' does not look like in IP Address (octet '$OCTET' in not in range 0-255).";
                        exit 1;

return 0;
Answered By: Franck Dernoncourt

I run a cloud service for my family and I made this quick script I run in a cron every morning at 5 because I am cheap an will not buy a static IP.

It grabs the public IP, and emails it to my users. Made it email in hyperlink format so my Mom does not have to type the ports or anything. Maybe someone else can use it to.

ipvariable=$(wget -O - -q);

echo "Today the location is http://$ipvariable:123456/foldertheyreach" | mail -s   "From your friendly cloud service provider",
Answered By: Will

The w3m Plaintext-Browser is great for the bash. You can use grep and tail to shorten the reply as follows:

w3m -no-cookie -dump "" | grep -A 1 -m 1 "Your IP:" | tail -n 1
Answered By: McPeppr supports:

nslookup .

IPv4 and IPv6, even more stuff with curl:

Answered By: Eun

I have setup a service that returns IP address as JSON / XML or plain text. You can find them here

Same URL with /json and /xml will give you other formats as well

If you want HTTPS you can use the same URLs with https prefix. The advantage being that even if you are on a Wifi you will get the public address.

So a simple alias myip=”curl” will get your IP

Answered By: vivekv

This will show the current ip address in a popup window:

zenity --info --text "$(curl -s"
Answered By: basic6

NOTE: This is about external IP address (the one that the servers on the Internet see when you connect to them) – if you want internal IP address (the one that your own computer is using for connections, which may be different) see this answer.

TL;DR – Fastest methods in 2015

The fastest method using DNS:

dig +short

or using externalip:

externalip dns

The fastest using HTTP:

curl -s

or using externalip:

externalip http

The fastest using HTTPS with a valid cert:

curl -s

or using externalip:

externalip https

Using telnet:

With nc command:

nc 23 | grep IPv4 | cut -d' ' -f4

or using externalip:

externalip telnet

With telnet command:

telnet 2>&1 | grep IPv4 | cut -d' ' -f4

Using FTP:

echo close | ftp | awk '{print $4; exit}'

or using externalip:

externalip ftp

All of the above can be run using my externalip script as:

externalip dns
externalip http
externalip https
externalip telnet
externalip ftp

Now a long story…

There are a lot of options of different servers providing the external IP especially via HTTP posted here or elsewhere.

I made a benchmark to see if any of them are better than the others and I was surprised by the results. E.g. one of the most widely recommended was almost always the slowest for me, sometimes taking many seconds to respond. Many don’t work over HTTPS, or do work but have invalid certificates. Some have very inconsistent response times.



This is the source of my externalip-benchmark script that I used:

You can run it yourself to see which services mentioned here are worth using:

chmod a+x externalip-benchmark

My results that I got on 2015-04-03 from Warsaw – the addresses have been changed to protect the innocent:

Best http response times:

0.086s - answer=''
0.089s - answer=''
0.091s - answer=''
0.117s - answer=''
0.156s - answer=''
0.317s - answer=''
0.336s - answer=''
0.338s - answer=''
0.347s - answer=''
0.496s - answer=''
0.527s - answer=''
0.548s - answer=''
0.665s - answer=''
0.665s - answer=''
1.041s - answer=''
1.049s - answer=''
1.598s - answer=''

Best https response times:

0.028s - answer=''
0.028s - answer=''
0.029s - answer=''
0.029s - answer=''
0.072s - answer=''
0.113s - answer=''
0.117s - answer=''
0.207s - answer=''
0.214s - answer=''
0.259s - answer=''
0.289s - answer=''
0.436s - answer=''
0.448s - answer=''
0.454s - answer=''
0.673s - answer=''
5.255s - answer=''
10.000s - answer=''

(Note: there are some fast responses with empty content – those are invalid.)

Best average ping times:

10.210 //
36.820 //
37.169 //
39.412 //
40.967 //
41.257 //
43.918 //
45.720 //
64.749 //
123.412 //
134.245 //
157.997 //
161.613 //
162.100 //
268.734 //
999999 //
999999 //

Here are the results that I got on 2015-04-03 from Amsterdam:

Best http response times:

0.021s - answer=''
0.027s - answer=''
0.035s - answer=''
0.039s - answer=''
0.045s - answer=''
0.142s - answer=''
0.144s - answer=''
0.150s - answer=''
0.150s - answer=''
0.170s - answer=''
0.190s - answer=''
0.191s - answer=''
0.301s - answer=''
0.330s - answer=''
0.343s - answer=''
0.485s - answer=''
3.549s - answer=''

Best https response times:

0.004s - answer=''
0.012s - answer=''
0.012s - answer=''
0.016s - answer=''
0.071s - answer=''
0.096s - answer=''
0.097s - answer=''
0.187s - answer=''
0.187s - answer=''
0.189s - answer=''
0.195s - answer=''
0.253s - answer=''
0.300s - answer=''
0.324s - answer=''
0.512s - answer=''
1.272s - answer=''
10.002s - answer=''

Best average ping times:

1.020 //
1.087 //
5.011 //
6.942 //
7.017 //
8.209 //
11.343 //
12.647 //
13.828 //
81.642 //
85.447 //
91.473 //
102.569 //
102.627 //
247.052 //
999999 //
999999 //

(The 999999 pings mean 100% packet loss.)


For a comparison here are times that other methods take – tested on 2015-06-16 from Warsaw and Amsterdam.


time dig +short

usually takes (real wall clock time) about:

  • 0.035s from Warsaw
  • 0.015s from Amsterdam

There are actually four resolvers that can be used this way:


They all give the same response times in Warsaw and Amsterdam but this may not be the case in other locations.

Using – the IP of instead of its domain name is faster:

  • 0.023s from Warsaw
  • 0.009s from Amsterdam

but may not work in the future if the IP ever changes (though it may be unlikely for a well known DNS resolver – maybe I should use the IP in my externalip script – please comment).


Telnet with nc or telnet command (see above) usually takes:

  • 0.103s from Warsaw
  • 0.035s from Amsterdam

(There is no noticeable difference between nc and telnet commands.)


  • 0.104s from Warsaw
  • 0.036s from Amsterdam

Domain names

All of the methods will be faster (especially when run for the first time) when IP addresses will be used instead of the domain names of the given services (except with HTTP that can use host-based virtual servers and not work with bare IP – not tested) but will stop working when the services change the IP address so it may be faster but less future-proof.


If you see some interesting results from your location, or if you think that some other hosts should be recommended instead of those that I’ve chosen, please post a comment. If there is any important service missing, please comment or post an issue on GitHub. I’d like to keep this post updated with a current choice of best-performing services.

Answered By: rsp

Alternatively you could use STUN which was invented to answer this question in an automated way and is used extensively in internet communications e.g. by SIP and WebRTC.

Using a stunclient (on debian/ubuntu do apt-get install stuntman-client) simply do:

$ stunclient
Binding test: success
Local address: A.B.C.D:42541
Mapped address: W.X.Y.Z:42541

where A.B.C.D is the IP address of your machine on the local net and W.X.Y.Z is the IP address servers like websites see from the outside (and the one you are looking for). Using sed you can reduce the output above to only an IP address:

stunclient |
    sed -ne "s/^Mapped address: (.*):.*$/1/p"

For an alternative STUN lookup using nothing but basic command line tools see
my answer on AskUbuntu (intended as a fun exercise, not for production use).

Answered By: Victor Klos

Amazon AWS


Sample output:

Also works on browser:

I like it because:

  • it returns just the plaintext IP in the reply body, nothing else
  • it is from a well known provider which is unlikely to go offline anytime soon

If after reading all these suggestions you want to read even more, here is an arguably over-engineered Bash script.

It contains a list of DNS and HTTP servers which seem to work fine as of February 2017.

If you have dig, it first tries DNS which is almost an order of magnitude faster that the various HTTP services.

It exits at the first reply it gets.

If you don’t have dig or if all DNS servers failed, it then tries the HTTP services until it gets a reply.

The servers are listed alphabetically, but are shuffled before use to avoid always using the same one.


## Get my external IP

timeout=2   # seconds to wait for a reply before trying next server
verbose=1   # prints which server was used to STDERR

    "dig +short  "
    "dig +short  "
    "dig +short  "
    "dig +short  "
    "dig +short    -t txt"
    "dig +short -4 -t a"
    "dig +short  "


# function to shuffle the global array "array"
shuffle() {
   local i tmp size max rand
   max=$(( 32768 / size * size ))
   for ((i=size-1; i>0; i--)); do
      while (( (rand=$RANDOM) >= max )); do :; done
      rand=$(( rand % (i+1) ))
      tmp=${array[i]} array[i]=${array[rand]} array[rand]=$tmp

## if we have dig and a list of dns methods, try that first
if hash dig 2>/dev/null && [ ${#dnslist[*]} -gt 0 ]; then
    eval array=( "${dnslist[@]}" )

    for cmd in "${array[@]}"; do
        [ "$verbose" == 1 ] && echo Trying: $cmd 1>&2
        ip=$(timeout $timeout $cmd)
        if [ -n "$ip" ]; then
            echo $ip

# if we haven't succeeded with DNS, try HTTP

if [ ${#httplist[*]} == 0 ]; then
    echo "No hosts in httplist array!" >&2
    exit 1

# use curl or wget, depending on which one we find
curl_or_wget=$(if hash curl 2>/dev/null; then echo "curl -s"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi);

if [ -z "$curl_or_wget" ]; then
    echo "Neither curl nor wget found. Cannot use http method." >&2
    exit 1

eval array=( "${httplist[@]}" )

for url in "${array[@]}"; do
    [ "$verbose" == 1 ] && echo Trying: $curl_or_wget  "$url" 1>&2
    ip=$(timeout $timeout $curl_or_wget "$url")
    if [ -n "$ip" ]; then
        echo $ip

Sample usage (I called the script myip):

$ myip
Trying: dig +short -t txt

$ ip=$(myip); echo "IP = '$ip'"
Trying: dig +short
IP = ''

Comment out the verbose variable at the top of the script to avoid printing the server used.

Update: this script is now also on Github where I might update it when needed:

Answered By: mivk

Using a DNS request even behind a NAT router translating DNS addresses, this can work :

$ dig +short -t txt | cut -d'"' -f2

or, you can use the HTTP request method instead :

$ curl -s
Answered By: SebMa

If any of you host an Internet-facing webserver, you can just make a simple page that will show the requester’s IP address, e.g. in PHP:


    echo $_SERVER['REMOTE_ADDR'];   


Deploy this on your server. e.g. at Then use the standard curl trick to retrieve it:

curl -s

Note that if your server does any redirects (such as, from HTTP to HTTPS) you’ll get the redirect response rather than your IP address. So address the curl request correctly.

The advantage of this approach is that the service won’t move or disappear out from under you, as happens so often with free services. Disadvantage is obviously that it will likely be slower, unless you have some high-end hosting.

Answered By: fear_no_eval

Only returned the correct IP by http, without https. Here are a few more http sites that return our public IP, and can do https. I learned here that using https instead of http on a wireless link will bypass ISP mangling of the IP, as several people said. Erwin Hoffman added "curve" encrypted dns to dnscache, which I could try with dig, since I have that here.

myip() shell func to consult a list of http sites or use https:

# ~/bin/.bash/.ifaces
myip() {
 [[ "$1" =~ -s ]] && s='https://' || s=''
 ( for site in
    do echo "$site "
    wget -qO- ${s}$site
   wget -qO- ${s} |
     sed -n -E '/IP Address/s/^.*:[t ]+([^<]+).*$/ n1/p' ) |
      sed -n -E '/^$/d;H;${g;s/^[n]+//;s/( )n/ /g;p;}'
 wget -qO- ${s} | sed '1s/.*/;$d;'

myip (without https): (without https but this one gets it)
  "ip": "",
  "hostname": "",
  "city": "Dallas",
  "region": "Texas",
  "country": "US",
  "loc": "32.7831,-96.8067",
  "org": "AS20057 AT&T Mobility LLC",
  "postal": "75270",
  "timezone": "America/Chicago",
  "readme": ""

myip -s (with https):
  "ip": "",
  "hostname": "",
  "city": "Dallas",
  "region": "Texas",
  "country": "US",
  "loc": "32.7831,-96.8067",
  "org": "AS20057 AT&T Mobility LLC",
  "postal": "75270",
  "timezone": "America/Chicago",
  "readme": ""
Answered By: BobDodds

you can do it using only bash like this

exec 3<>/dev/tcp/ 
echo -e 'GET / HTTP/1.0rnhost: icanhazip.comrnr' >&3 
while read i
 [ "$i" ] && myip="$i" 
done <&3 
echo "$myip"

bash opens a TCP socket to icanhazip and sends an http request, the IP address is returned on the last non-empty line of the data returned. (previous lines are http headers)

This avoids the need for http client like wget or curl.

Answered By: Jasen

All of the above answers assume that the local machine has a domain name that can be resolved by a dns server.

This answer helps if

  • the local machine does not have a domain name that can be resolved by a dns server
  • you want to be independent from a domain name
  • you want the LAN ip address in the local network not the WAN ip of your router

This can be used in a shell script:

# Determine relevant network interface (e.g. eth0 on Linux, en0 on Mac)
INTERFACE=`ifconfig | grep -Eo '^e[a-z]+0: flags=.*' | grep -Eo '^e[a-z]+0'`
# Determine the external ip on this interface
HOSTIP=`ifconfig $INTERFACE | grep -Eo 'inet (addr:)?([0-9]*.){3}[0-9]*' | grep -Eo '([0-9]*.){3}[0-9]*'` 

Does not work on Windows though.

Answered By: not2savvy
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.