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

346

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

    
por Eugene Yarmash 15.09.2011 / 16:43

23 respostas

444

Você pode usar getent , que vem com glibc (então é quase certo que você o tenha no Linux). Isso resolve usando gethostbyaddr / gethostbyname2 e, portanto, verificará /etc/hosts / NIS / etc:

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

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

dig +short unix.stackexchange.com

Se dig +short estiver indisponível, qualquer um dos itens a seguir deverá 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 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 }'
    
por 15.09.2011 / 18:29
127

Com host do pacote dnsutils :

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

( Corrigido nome do pacote de acordo com os comentários. Como nota outras distribuições possuem host é pacotes diferentes: Ubuntu bind9-host , openSUSE bind utils , Frugalware bind .)

    
por 15.09.2011 / 16:50
51

Eu tenho uma ferramenta na minha máquina que parece fazer o trabalho. A página man mostra que ele vem 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 ...

    
por 15.09.2011 / 23:50
41

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. Assim, você precisaria 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

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

    
por 15.09.2011 / 20:23
34
getent hosts unix.stackexchange.com | cut -d' ' -f1
    
por 04.10.2013 / 21:12
26

As soluções dadas até agora funcionam principalmente no caso mais simples: o nome do host resolve diretamente para um único endereço IPv4. Este pode ser o único caso em que você precisa resolver os nomes dos hosts, mas se não, abaixo está uma discussão sobre alguns casos que você pode precisar manipular.

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

Portanto, www.google.com não resolve diretamente para endereços IP, mas para um alias que resolve para vários endereços IP. Para mais informações sobre aliases, consulte aqui . Naturalmente, o caso em que um alias tem um único endereço IP é possível, conforme 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 resolve um alias que não resolve um endereço IP, mas acho que o caso pode ocorrer.

Mais do que vários endereços IP e aliases, existem alguns 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

Em que o nome do host ipv6.google.com é um nome de host somente IPv6. E quanto a 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::
Mais uma vez sobre o IPv6, se o seu host é apenas IPv4, você ainda pode resolver os endereços IPv6 (testado em um WinXP apenas IPv4 e com ipv6.google.com, você poderia experimentá-lo no Linux). Nesse caso, a resolução é bem-sucedida, mas um ping falha com uma mensagem de erro do host desconhecido . Isso pode ser um caso em que seu script falha.

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

    
por 21.09.2011 / 17:13
17

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

python -c 'import socket; print socket.gethostbyname("www.example.com")'
    
por 12.09.2012 / 11:34
16
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)

    
por 10.08.2012 / 23:20
14

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 receberá 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 de preferência do proprietário, o que pode ser o endereço IPv4 ou IPv6.

    
por 15.06.2014 / 16:42
5

Aqui está uma pequena variação da abordagem ping que leva "host desconhecido" em conta (passando por 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}'
    
por 04.10.2013 / 17:22
5

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

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

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

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

    $ dig -v
    DiG 9.8.1-P1
    
por 30.09.2014 / 17:26
4

Você pode 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
    
por 15.09.2011 / 17:01
3
 php -r "echo gethostbyname('unix.stackexchange.com');"
    
por 30.04.2015 / 00:01
3
nmap -sP 192.168.178.0/24|grep YOUR_HOSTNAME|sed -n 's/.*[(]\([0-9\.]*\)[)].*//p'

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

    
por 14.08.2015 / 17:07
3

Gostaria de acrescentar isso como um comentário ao Andrew McGregor Re: ping. No entanto, isso não me deixaria, então eu preciso adicionar isso como outra resposta. (Se alguém puder movê-lo para um comentário, sinta-se à vontade para fazê-lo.)

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

    
por 03.11.2016 / 18:31
2

aqui está uma receita de Bash que eu criei usando as respostas de outras pessoas - primeiro tenta /etc/hosts e depois volta para 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
}
    
por 11.01.2014 / 02:16
2

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 IP IPv4, assim como retornará 1 no 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

Google's IP is 216.58.192.46.

Se você quiser um endereço IPv6, basta substituir -4 por -6 .

    
por 04.08.2015 / 21:47
2

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

    
por 17.03.2016 / 22:03
1

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
    
por 23.03.2017 / 10:59
1

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

Então, escrevi um wrapper estúpido para dns.lookup para você que tem o Node.js instalado para fornecer uma CLI:

$ npm install -g lookup-hostname
$ lookup google.com
62.243.192.89
    
por 14.05.2017 / 02:16
1

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'
    
por 14.11.2017 / 04:40
1

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

ping -a hostname -c 1

Irá ping do 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
    
por 27.10.2017 / 08:12
-1
host -t a cisco.com

este comando irá mostrar o endereço IP (irá reslover o domínio para IP)

    
por 27.09.2018 / 18:55