desenv-web-rp.com

Como posso resolver um nome de host para um endereço IP em um script Bash?

Qual é a maneira mais concisa de resolver um nome de host para um endereço IP em um script Bash? Estou usando Arch Linux .

450
Eugene Yarmash

Você pode usar getent, que vem com glibc (então você quase certamente o possui no Linux). Isso resolve usando gethostbyaddr/gethostbyname2 e também verifica /etc/hosts/NIS/etc:

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

Ou, como Heinzi disse abaixo, você pode usar Dig com o +short argumento (consulta servidores DNS diretamente, não analisa /etc/hosts/NSS/etc):

Dig +short unix.stackexchange.com

E se Dig +short está indisponível, qualquer um dos seguintes deve funcionar. Todos eles consultam o DNS diretamente e ignoram outros meios de resolução:

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 }'

Se você deseja imprimir apenas um IP, adicione o comando exit ao fluxo de trabalho 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

Com Host do pacote dnsutils :

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

( Nome do pacote corrigido de acordo com os comentários. Como uma nota, outras distribuições têm Host em diferentes pacotes: Debian/Ubuntu bind9-Host, openSUSE bind-utils, Frugalware bind.)

146
manatwork

Eu tenho uma ferramenta na minha máquina que parece fazer o trabalho. A página de manual mostra que parece vir com o mysql ... Aqui está como você pode usá-lo:

resolveip -s unix.stackexchange.com
64.34.119.12

O valor de retorno desta ferramenta é diferente de 0 se o nome do host não puder ser resolvido:

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

UPDATE No Fedora, ele vem com o 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

Eu acho que isso criaria uma dependência estranha para o seu script ...

56
greg0ire

O seguinte comando usando Dig permite que você leia o resultado diretamente, sem nenhum sed/awk/etc. Magia:

$ Dig +short unix.stackexchange.com
64.34.119.12

Dig também está incluído no pacote dnsutils.


Nota: Dig tem um valor de retorno de 0, mesmo que o nome não possa ser resolvido. Portanto, você precisa verificar se a saída está vazia em vez de verificar o valor de retorno:

hostname=unix.stackexchange.com

ip=`Dig +short $hostname`

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

Nota 2: se um nome de host tiver vários endereços IP (tente debian.org, por exemplo), todos eles serão retornados. Esse "problema" afeta todas as ferramentas mencionadas nesta pergunta até o momento:

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

As soluções fornecidas até agora funcionam principalmente no caso mais simples: o nome do host é resolvido diretamente para um único endereço IPv4. Este pode ser o único caso em que você precisa resolver nomes de host, mas, se não, a seguir, é apresentada uma discussão sobre alguns casos com os quais você pode precisar lidar.

Chris Down e Heinzi discutiram brevemente o caso em que o nome do host resolve para mais de um endereço IP. Nesse caso (e outros abaixo), os scripts básicos sob a suposição de que um nome de host seja resolvido diretamente para um único endereço IP podem ser interrompidos. Abaixo, um exemplo com um nome de host resolvido para mais de um único endereço 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

Mas o que é www.l.google.com? É aqui que o caso alias precisa ser introduzido. Vamos verificar o exemplo abaixo:

$ 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

Assim www.google.com não resolve diretamente para endereços IP, mas para um alias que resolve sozinho para vários endereços IP. Para mais informações sobre aliases, consulte aqui . Obviamente, é possível o caso em que um alias tem um único endereço IP, como mostrado abaixo:

$ 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

Mas os aliases podem ser encadeados? A resposta é sim:

$ 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

Não encontrei nenhum exemplo em que um nome de host resolva um alias que não seja um endereço IP, mas acho que o caso pode ocorrer.

Mais do que vários endereços IP e aliases, existem outros casos especiais ... e o IPv6? Você poderia tentar:

$ 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

Onde o nome do host ipv6.google.com é um nome de host somente para IPv6. E os nomes de host de pilha dupla:

$ 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::

Novamente sobre o IPv6, se o seu host for apenas IPv4, você ainda poderá resolver endereços IPv6 (testado em um WinXP somente para IPv4 e com o ipv6.google.com, você poderá experimentá-lo no Linux). Nesse caso, a resolução é bem-sucedida, mas um ping falha com uma mensagem de erro de host desconhecida. Pode ser um caso em que seu script falha.

Espero que essas observações tenham sido úteis.

30
jfg956

Para evitar o problema com aliases e sempre prepare um único endereço IP para uso:

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

Simples, mas útil:

  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

Todos os comandos resolverão um endereço IP se o host ainda existir. Se o Host apontar para CNAME, ele também obterá o IP nesse caso.

O primeiro comando retorna o endereço IPv4 resolvido

O segundo comando retorna o endereço IPv6 resolvido

O terceiro comando retornará o endereço preferido dos proprietários, o que pode ser endereçado por IPv4 ou IPv6.

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

funciona sem dependências em outros sistemas (e para hosts especificados em/etc/hosts)

19
Andrew McGregor

Aqui está uma ligeira variação da abordagem ping que leva em consideração "Host desconhecido" (através do stderr) e usa tr para evitar o uso de sed regexps:

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

Caso seja importante capturar o valor de saída, o seguinte funcionará (embora menos elegante):

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

Para concluir a resposta de Chris Down e abordar os comentários do jfgagne sobre aliases (possivelmente encadeados), aqui está uma solução que:

  • leva em consideração vários IPs
  • leva em conta um ou mais aliases (CNAME)
  • não consulta /etc/hosts file (no meu caso eu não o queria); para consultá-lo, dbernt's python é perfeita)
  • não usa awk/sed

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

Sempre retorna o primeiro endereço IP ou tring vazio, se não for resolvido. com a versão do Dig:

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

Gostaria de adicionar isso como um comentário a Andrew McGregor Re: ping. No entanto, não me deixou, por isso preciso adicionar isso como outra resposta. (Se alguém puder colocá-lo em um comentário, sinta-se à vontade.)

Esta é outra variante, usando apenas ping e grep:

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

grep -E para expressão regular estendida e grep -o para retornar apenas a parte correspondente. o próprio regexp procura um ou vários dígitos ([0-9]+) e, opcionalmente, um ponto (\.?) quatro vezes ({4})

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

foi a solução que encontrei sem o servidor DNS

5
Philippe Gachoud

aqui está uma receita do Bash que preparei usando as respostas de outras pessoas - primeiras tentativas /etc/hosts, depois volta ao 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

Você poderia usar 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

Talvez não seja o mais conciso, mas parece ser robusto e eficiente:

# $(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
}

Isso produzirá um único IPv4, bem como retornará 1 em caso de falha, mascarando a saída stderr.

Você pode usá-lo assim:

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

O IP do Google é 216.58.192.46.

Se você deseja um endereço IPv6, substitua -4 com -6.

4
Will

Dig é muito lento, nslookup é muito mais rápido

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 linha resolve uma lista de nome de host

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

Não sei a maneira mais fácil para um script bash, mas se você quiser resolver um nome de host e ver se o host está ativo, use ping!

ping -a hostname -c 1

ping o host uma vez e resolverá o nome do host para o endereço 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

Estou fazendo isso o tempo todo no meu Mac, que não possui getent. ping parece um hack. Eu gostaria de levar /etc/hosts em consideração também.

Então, eu escrevi um invólucro estúpido para dns.lookup para você que possui o Node.js instalado para fornecer uma 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

Sim, já existem muitas respostas, mas falta uma solução usando o Perl:

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

Em um script bash, poderia ser usado assim:

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

Os módulos usados ​​aqui são módulos principais, portanto devem estar disponíveis em qualquer lugar sem a instalação com o CPAN.

2
Slaven Rezic