web-dev-qa-db-fra.com

Comment puis-je résoudre un nom d'hôte en une adresse IP dans un script Bash?

Quelle est la manière la plus concise de résoudre un nom d'hôte en une adresse IP dans un script Bash? J'utilise Arch Linux .

450
Eugene Yarmash

Vous pouvez utiliser getent, qui vient avec glibc (donc vous l'avez presque certainement sur Linux). Cela se résout en utilisant gethostbyaddr/gethostbyname2, et vérifiera également /etc/hosts/NIS/etc:

getent hosts unix.stackexchange.com | awk '{ print $1 }'

Ou, comme Heinzi l'a dit ci-dessous, vous pouvez utiliser Dig avec le +short argument (interroge directement les serveurs DNS, ne regarde pas /etc/hosts/NSS/etc):

Dig +short unix.stackexchange.com

Si Dig +short n'est pas disponible, l'un des éléments suivants devrait fonctionner. Toutes ces requêtes DNS directement et ignorent les autres moyens de résolution:

Host unix.stackexchange.com | awk '/has address/ { print $4 }'
nslookup unix.stackexchange.com | awk '/^Address: / { print $2 }'
Dig unix.stackexchange.com | awk '/^;; ANSWER SECTION:$/ { getline ; print $5 }'

Si vous ne souhaitez imprimer qu'une seule adresse IP, ajoutez la commande exit au flux de travail de awk.

Dig +short unix.stackexchange.com | awk '{ print ; exit }'
getent hosts unix.stackexchange.com | awk '{ print $1 ; exit }'
Host unix.stackexchange.com | awk '/has address/ { print $4 ; exit }'
nslookup unix.stackexchange.com | awk '/^Address: / { print $2 ; exit }'
Dig unix.stackexchange.com | awk '/^;; ANSWER SECTION:$/ { getline ; print $5 ; exit }'
570
Chris Down

Avec Host du paquet dnsutils :

$ Host unix.stackexchange.com
unix.stackexchange.com has address 64.34.119.12

( Nom du paquet corrigé selon les commentaires. À noter que d'autres distributions ont Host dans différents paquets: Debian/Ubuntu bind9-Host, openSUSE bind-utils, Frugalware bind.)

146
manatwork

J'ai un outil sur ma machine qui semble faire l'affaire. La page de manuel montre qu'il semble venir avec mysql ... Voici comment vous pouvez l'utiliser:

resolveip -s unix.stackexchange.com
64.34.119.12

La valeur de retour de cet outil est différente de 0 si le nom d'hôte ne peut pas être résolu:

resolveip -s unix.stackexchange.coma
resolveip: Unable to find hostid for 'unix.stackexchange.coma': Host not found
exit 2

UPDATE Sur Fedora, il est livré avec mysql-server:

yum provides "*/resolveip"
mysql-server-5.5.10-2.fc15.x86_64 : The MySQL server and related files
Dépôt         : Fedora
Correspondance depuis :
Nom de fichier      : /usr/bin/resolveip

Je suppose que cela créerait une étrange dépendance pour votre script ...

56
greg0ire

La commande suivante utilisant Dig vous permet de lire le résultat directement sans sed/awk/etc. la magie:

$ Dig +short unix.stackexchange.com
64.34.119.12

Dig est également inclus dans le package dnsutils.


Remarque: Dig a une valeur de retour de 0, même si le nom n'a pas pu être résolu. Ainsi, vous devrez vérifier si la sortie est vide au lieu de vérifier la valeur de retour:

hostname=unix.stackexchange.com

ip=`Dig +short $hostname`

if [ -n "$ip" ]; then
    echo IP: $ip
else
    echo Could not resolve hostname.
fi

Remarque 2: si un nom d'hôte possède plusieurs adresses IP (essayez debian.org, par exemple), tous seront retournés. Ce "problème" affecte jusqu'à présent tous les outils mentionnés dans cette question:

45
Heinzi
getent hosts unix.stackexchange.com | cut -d' ' -f1
44
sborsky

Les solutions proposées jusqu'à présent fonctionnent principalement dans le cas le plus simple: le nom d'hôte se résout directement en une seule adresse IPv4. Cela peut être le seul cas où vous devez résoudre les noms d'hôte, mais sinon, vous trouverez ci-dessous une discussion sur certains cas que vous devrez peut-être gérer.

Chris Down et Heinzi ont brièvement discuté du cas où le nom d'hôte se résout en plusieurs adresses IP. Dans ce cas (et dans d'autres ci-dessous), les scripts de base sous l'hypothèse qu'un nom d'hôte se résout directement en une seule adresse IP peuvent se casser. Ci-dessous, un exemple avec un nom d'hôte se résolvant à plusieurs adresses IP:

$ Host www.l.google.com
www.l.google.com has address 209.85.148.147
www.l.google.com has address 209.85.148.103
www.l.google.com has address 209.85.148.99
www.l.google.com has address 209.85.148.106
www.l.google.com has address 209.85.148.105
www.l.google.com has address 209.85.148.104

Mais comment ça www.l.google.com? C'est là que le cas d'alias doit être introduit. Vérifions l'exemple ci-dessous:

$ Host www.google.com
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 74.125.39.103
www.l.google.com has address 74.125.39.147
www.l.google.com has address 74.125.39.105
www.l.google.com has address 74.125.39.99
www.l.google.com has address 74.125.39.106
www.l.google.com has address 74.125.39.104

Donc www.google.com ne se résout pas directement aux adresses IP, mais à un alias qui se résout lui-même à plusieurs adresses IP. Pour plus d'informations sur les alias, consultez ici . Bien sûr, le cas où un alias a une seule adresse IP est possible, comme indiqué ci-dessous:

$ Host g.www.ms.akadns.net
g.www.ms.akadns.net is an alias for lb1.www.ms.akadns.net.
lb1.www.ms.akadns.net has address 207.46.19.190

Mais les alias peuvent-ils être enchaînés? La réponse est oui:

$ Host www.Microsoft.com
www.Microsoft.com is an alias for toggle.www.ms.akadns.net.
toggle.www.ms.akadns.net is an alias for g.www.ms.akadns.net.
g.www.ms.akadns.net is an alias for lb1.www.ms.akadns.net.
lb1.www.ms.akadns.net has address 207.46.19.254

$ Host www.google.fr
www.google.fr is an alias for www.google.com.
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 74.125.39.147
www.l.google.com has address 74.125.39.103
www.l.google.com has address 74.125.39.99
www.l.google.com has address 74.125.39.106
www.l.google.com has address 74.125.39.104
www.l.google.com has address 74.125.39.105

Je n'ai trouvé aucun exemple où un nom d'hôte se résout en un alias qui ne se résout pas en une adresse IP, mais je pense que le cas peut se produire.

Plus que plusieurs adresses IP et alias, existe-t-il d'autres cas particuliers ... qu'en est-il d'IPv6? Tu pourrais essayer:

$ Host ipv6.google.com
ipv6.google.com is an alias for ipv6.l.google.com.
ipv6.l.google.com has IPv6 address 2a00:1450:8007::68

Où le nom d'hôte ipv6.google.com est un nom d'hôte uniquement IPv6. Qu'en est-il des noms d'hôte à double pile:

$ Host www.facebook.com
www.facebook.com has address 66.220.153.15
www.facebook.com has IPv6 address 2620:0:1c08:4000:face:b00c::

Encore une fois à propos d'IPv6, si votre hôte est uniquement IPv4, vous pouvez toujours résoudre les adresses IPv6 (testé sur IPv4 uniquement WinXP et avec ipv6.google.com, vous pouvez l'essayer sous Linux). Dans ce cas, la résolution réussit, mais un ping échoue avec un message d'erreur hôte inconnu. Il peut s'agir d'un cas où votre script échoue.

J'espère que ces remarques ont été utiles.

30
jfg956

Pour éviter le problème avec les alias et toujours obtenir une seule adresse IP prête à l'emploi:

python -c 'import socket; print socket.gethostbyname("www.example.com")'
22
dbernt

Simple mais utile:

  1. getent ahostsv4 www.google.de | grep STREAM | head -n 1 | cut -d ' ' -f 1
  2. getent ahostsv6 www.google.de | grep STREAM | head -n 1 | cut -d ' ' -f 1
  3. getent hosts google.de | head -n 1 | cut -d ' ' -f 1

Toutes les commandes résoudront une adresse IP si l'hôte existe toujours. Si l'hôte pointe vers CNAME, il obtiendra également l'IP dans ce cas.

La première commande renvoie l'adresse IPv4 résolue

La deuxième commande renvoie l'adresse IPv6 résolue

La troisième commande renverra l'adresse préférée des propriétaires, à savoir l'adresse IPv4 ou IPv6.

19
Tom Freudenberg
ping -q -c 1 -t 1 your_Host_here | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"

fonctionne sans dépendances sur d'autres systèmes (et pour les hôtes spécifiés dans/etc/hosts)

19
Andrew McGregor

Voici une légère variation de l'approche ping qui prend en compte "Host inconnu" (en passant par stderr) et utilise tr pour éviter l'utilisation de sed regexps:

ping -c1 -t1 -W0 www.example.com 2>&1 | tr -d '():' | awk '/^PING/{print $3}'

Dans le cas où il est important de capturer la valeur de sortie, les éléments suivants fonctionneront (bien que moins élégants):

ping -c1 -t1 -W0 www.example.com &>/dev/null && ping -c1 -t1 -W0 www.example.com 2>&1 | tr -d '():' | awk '/^PING/{print $3}'
9
Stefan Farestam

Pour compléter la réponse de Chris Down et répondre aux commentaires de jfgagne sur les alias (éventuellement chaînés), voici une solution qui:

  • prend en compte plusieurs IP
  • prend en compte un ou plusieurs alias (CNAME)
  • ne demande pas /etc/hosts fichier (dans mon cas, je ne le voulais pas); pour l'interroger, la solution python de dbernt est parfaite)
  • n'utilise pas awk/sed

    Dig +short www.alias.com  | grep -v "\.$" | head -n 1
    

Renvoie toujours la première adresse IP, ou vide si elle n'est pas résolue. avec la version de Dig:

    $ Dig -v
    Dig 9.8.1-P1
8
Franck
 php -r "echo gethostbyname('unix.stackexchange.com');"
6
Mohammed Zourob

J'aurais aimé ajouter ceci comme commentaire à Andrew McGregor Re: ping. Cependant, cela ne me permettrait pas, donc je dois ajouter ceci comme une autre réponse. (Si quelqu'un peut le déplacer dans un commentaire, n'hésitez pas à le faire.)

Ceci est une autre variante, utilisant uniquement ping et grep:

ping -q -c1 -t1 your_Host_here | grep -Eo "([0-9]+\.?){4}"

grep -E pour l'expression régulière étendue et grep -o pour renvoyer uniquement la partie correspondante. l'expression rationnelle elle-même recherche un ou plusieurs chiffres ([0-9]+) et éventuellement un point (\.?) quatre fois ({4})

6
Dweia
nmap -sP 192.168.178.0/24|grep YOUR_HOSTNAME|sed -n 's/.*[(]\([0-9\.]*\)[)].*/\1/p'

était la solution que j'ai trouvée sans serveur DNS

5
Philippe Gachoud

voici une recette Bash que j'ai concoctée en utilisant les réponses d'autres personnes - premiers essais /etc/hosts, puis revient à nslookup:

resolveip(){
    local Host="$1"
    if [ -z "$Host" ]
    then
        return 1
    else
        local ip=$( getent hosts "$Host" | awk '{print $1}' )
        if [ -z "$ip" ] 
        then
            ip=$( Dig +short "$Host" )
            if [ -z "$ip" ]
            then
                echo "unable to resolve '$Host'" >&2 
                return 1
            else
                echo "$ip"
                return 0
            fi
        else
            echo "$ip"
            return 0
        fi
    fi
}
5
RubyTuesdayDONO

Vous pouvez utiliser Host:

hostname=example.org

# strips the IP
IP=$( Host ${hostname} | sed -e "s/.*\ //" )

# checks for errors
if [ $? -ne 0 ] ; then
   echo "Error: cannot resolve ${hostname}" 1>&2
   exit 1;
fi
5
Matteo

Peut-être pas le plus concis, mais il semble être robuste et efficace:

# $(get_Host_dns_short "google.com")
#
# Outputs the IPv4 IP Address of a hostname, resolved by DNS. Returns 0 if DNS
# responded successfully; 1 otherwise. Will mask error output.
function get_Host_dns_short()
{
    (
        set -o pipefail

        Host -4 -W1 -t A "$1" 2>/dev/null | awk '/has address/ { print $NF; exit }'
    ) && return 0 || return 1
}

Cela produira une seule IP IPv4 et renverra 1 en cas de panne, tout en masquant la sortie stderr.

Vous pouvez l'utiliser comme ceci:

GOOGLE_IP="$(get_Host_dns_short "google.com")"
if [[ $? -eq 0 ]]; then
    echo "Google's IP is ${GOOGLE_IP}."
else
    echo "Failed to resolve Google's IP."
fi

L'IP de Google est 216.58.192.46.

Si vous souhaitez plutôt une adresse IPv6, remplacez simplement -4 avec -6.

4
Will

Dig est trop lent, nslookup est beaucoup plus rapide

nslookup google.com | grep -Po 'Address:\s*[0-9.]+' | tail -1 | sed -e 's/Address:\s*//g'
4
Andrey Izman

Dig +noall +answer +nocomments example.com | awk '{printf "%-36s\t%s\n", $1, $5 }'

4
D P Baker

1 ligne résout une liste de nom d'hôte

for LINE in `cat ~/Desktop/mylist`; do a=$(nslookup $LINE | awk '/^Address: / { print $1 }');  echo $a >> ~/Desktop/ip; done
3
Andy Wong

Je ne connais pas le moyen le plus simple pour un script bash mais si vous voulez résoudre un nom d'hôte et voir si l'hôte est en place, utilisez ping!

ping -a hostname -c 1

ping l'hôte une fois et résoudra le nom d'hôte en adresse IP.

$ ping -a www.google.com -c 1
PING www.google.com (216.58.211.132) 56(84) bytes of data.
64 bytes from arn09s10-in-f4.1e100.net (216.58.211.132): icmp_seq=1 ttl=54 time=1.51 ms
3
user257655

Je le fais tout le temps sur mon Mac qui n'a pas getent. ping ressemble à un hack. Je voudrais prendre /etc/hosts également.

J'ai donc écrit un emballage stupide pour dns.lookup pour vous qui avez installé Node.js pour fournir une CLI:

$ npm install -g lookup-hostname
$ lookup google.com
62.243.192.89
3
Thomas Jensen
#!/bin/bash

systemd-resolve   RT.com -t A  | awk '{ print $4 ; exit }'
systemd-resolve unix.stackexchange.com -t A --legend=no | awk '{ print $4 ; exit }'

resolveip -s      RT.com
Dig       +short  RT.com
Host              RT.com | awk '/has address/ { print $4 }'
nslookup          RT.com | awk '/^Address: /  { print $2 }'
ping -q -c 1 -t 1 RT.com | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"

Ruby     -rresolv -e      ' print    Resolv.getaddress "RT.com" '
python2  -c 'import socket; print socket.gethostbyname("RT.com")'
Perl     -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' RT.com  2>/dev/null
php      -r "echo gethostbyname( 'RT.com' );"

echo        "   all do work for me - take your pick!  "
2
dotbit

Oui, il existe déjà de nombreuses réponses, mais il manque une solution utilisant Perl:

Perl -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' unix.stackexchange.com

Dans un script bash, il pourrait être utilisé comme ceci:

#!/bin/bash
ipaddr=$(Perl -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' unix.stackexchange.com)
echo $ipaddr

Les modules utilisés ici sont des modules de base, donc devraient être disponibles partout sans installation avec CPAN.

2
Slaven Rezic