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 .

Comentários

  • Pena que a getent <ahosts|ahostsv4|ahostsv6|hosts> <hostname> resposta está em algum lugar perto do fundo. É ‘ é o mais simples, não requer pacotes extras e também é mais fácil de analisar a partir de um script Bash.
  • @ 0xC0000022L: A nova vergonha é que essa resposta sugere getent hosts somehost, quando executando isso enquanto em somehost produzirá um endereço IPv6 , que é diferente da maioria das outras ferramentas (ping, ssh pelo menos) resolve nomes e quebra algumas coisas. Use o ahosts em vez de hosts.
  • @j_random_hacker: que o impede de solicitar especificamente IPv4 (ahostsv4) ou endereços IPv6 (ahostsv6)? Pessoalmente, não encontro nada de errado com a solicitação inespecífica de retornar IPv6. Seu código deve estar preparado. IPv6 já existe há mais de 20 anos.
  • @ 0xC0000022L: Ninguém ” me impede ” de fazendo isso, mas a resposta sugere especificamente hosts, e até agora 4 pessoas votaram contra vinc17 ‘ o comentário que expressa a dor causada por ” de repente IPv6 “. Estar preparado para o IPv6 nem sempre é o problema: muitos programas precisam de uma maneira de determinar se dois nomes / endereços se referem ao mesmo host. Eles podem usar correspondência de string simples ou devem saber muito sobre a rede para encontrar a resposta ” verdadeira “. O último é um campo minado, tantos programas e sistemas de terceiros – sobre os quais não tenho controle – usam o primeiro.

Resposta

Você pode usar getent, que vem com glibc (então quase certamente você o tem no Linux) . Isso é resolvido usando gethostbyaddr / gethostbyname2 e, portanto, também 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 os servidores DNS diretamente, não olha para /etc/hosts / NSS / etc):

dig +short unix.stackexchange.com 

Se dig +short não estiver disponível, qualquer um do seguinte deve funcionar. Todos estes questionam 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 exit comando para awk” fluxo de trabalho.

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

Comentários

  • Por padrão, usar dig só funciona com ipv4, em que host fornece respostas ipv4 e ipv6. Isso pode ser inesperado. Você pode tentar host www.google.com, dig +short www.google.com, host ipv6.google.com, dig +short ipv6.google.com, host www.facebook.com , dig +short www.facebook.com.
  • DIG não funciona, se for um CNAME não retornará o IP.
  • Às vezes, host pode ser expirado e não retorna nada. Para alguns domínios, dig +short pode retornar um alias de domínio na primeira linha. Portanto, para garantir que a saída seja um IPv4 endereço, use dig +short example.com | grep -Eo '[0-9\.]{7,15}' | head -1.
  • Usar getent hosts <host> é incorreto, como para instan ce pode fornecer um endereço IPv6, enquanto o IPv6 não ‘ funciona. A solução correta é usar getent ahosts <host> para tentar IPv6 e IPv4 se necessário.
  • Vale a pena mencionar: host, dig e nslookup parecem se comunicar diretamente com os servidores listados no resolv.conf, enquanto ” getent hosts ” respeita o arquivo de hosts locais e o armazenamento em cache no nível da biblioteca (como nscd) se habilitado .

Resposta

Com host da 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. Observe que outras distribuições têm host em pacotes diferentes: Debian / Ubuntu bind9-host , openSUSE bind-utils , Frugalware bind .)

Comentários

  • Veja a entrada resolveip abaixo se precisar resolver algo que não está no DNS (por exemplo, / etc / hosts)
  • Esteja ciente de que host às vezes retorna uma saída multilinha (no caso de redirecionamentos), você ‘ vai querer host unix.stackexchange.com | tail -n1 se você quiser apenas a linha com o endereço IP.
  • Existem várias versões do ” host ” com diferentes formatos de saída. Por exemplo. a maioria dos sistemas parece ter a versão BIND9, mas meu servidor Ubuntu 10.04 LTS tem uma versão completamente diferente de alguma forma ..
  • se você não ‘ não tiver host ou dig instalado, você pode usar ping, que está sempre disponível: ping unix.stackexchange.com -c 1 -q 2>&1 | grep -Po "(\d{1,3}\.){3}\d{1,3}" isso não precisa de nenhum pacotes extras são instalados na maioria dos matchines Unix / Linux.
  • Essa resposta merece um downvote sério. host é uma ferramenta DNS (semelhante a nslookup), portanto, procura apenas hosts no DNS, não em, por exemplo, /etc/hosts. Portanto, NÃO é uma resposta à pergunta da OP ‘.

Resposta

Tenho uma ferramenta em minha máquina que parece funcionar. A página de manual mostra que parece vir com 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 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 

Acho que criaria uma dependência estranha para o seu script …

Comentários

  • Esta parece ser a única solução aqui que usa o SO ‘ s construído no resolvedor – então funciona para / etc / hosts, bem como DNS.
  • getent, conforme detalhado na outra resposta, também olha para / etc / hosts e vem com glibc, então não tem dependências em um sistema Linux.
  • Eu não usaria resolveip porque você cria uma dependência em outro pacote. getent é instalado por padrão. host, nslookup e dig estão todos em pacotes opcionais. Definitivamente, use getent em um script.
  • Gosto dessa resposta, mas ela não ‘ t retorna ipv6

Resposta

O seguinte comando usando dig permite que você leia o resultado diretamente sem qualquer sed / awk / etc. mágica:

$ dig +short unix.stackexchange.com 64.34.119.12 

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


Observação : dig tem um valor de retorno de 0, mesmo se o nome não puder 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 retornado. Este “problema” afeta todas as ferramentas mencionadas nesta pergunta até agora:

Comentários

  • Observe que se um domínio tiver uma entrada CNAME seu domínio pode ser impresso na primeira linha em vez de um endereço IP.

Resposta

getent hosts unix.stackexchange.com | cut -d" " -f1 

Comentários

  • Considere também ahosts, ahostsv4, ahostsv6 com getent.
  • cut não será para getent ‘ s, que usam \t para separar colunas. Esse é o caso no Solaris.
  • @ceving: No Sola ris você pode ter que executar cut sem -d (o padrão é \t como delimitador). No Linux, ele ‘ s espaços, portanto, a linha acima funciona.

Resposta

As soluções fornecidas 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 nomes de host, mas se não, abaixo está uma discussão sobre alguns casos que você pode precisar lidar.

Chris Down e Heinzi discutiram brevemente o caso em que o nome de host resolve para mais de um endereço IP. Nesse caso (e em outros a seguir), o script básico sob a suposição de que um nome de host é resolvido diretamente para um único endereço IP pode falhar. Abaixo, um exemplo com um nome de host resolvendo 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 é ? É aqui que o alias caso precisa ser introduzido. Vejamos 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 se resolve para vários endereços IP. Para obter mais informações sobre aliases, verifique aqui . Claro, 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 apelidos 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 para um alias que não resolve para um endereço IP, mas acho que o pode ocorrer caso.

Mais do que vários endereços IP e aliases, há alguns outros casos especiais … e quanto ao IPv6? Você pode 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 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 seu host for apenas IPv4, você ainda pode resolver endereços IPv6 (testado em um WinXP apenas IPv4 e com ipv6.google.com, você pode tentar no Linux). Nesse caso, a resolução é bem-sucedida, mas o ping falha com uma mensagem de erro de host desconhecido . Este pode ser um caso em que o seu script falha.

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

Comentários

  • Que ótimo complemento para a resposta aceita, mostrando todos os casos extremos com os quais se pode querer lidar no script. Minha versão host nem mesmo declara ” tem endereço ” para minhas caixas.

Resposta

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

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

Comentários

Resposta

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)

Comentários

  • O uso de ping é o que eu precisava, pois preciso do valor do arquivo hosts, mas o padrão sed analisando corretamente, mas funcionou ping – q -c 1 -t 1 your_host_here | grep PING | sed -e ” s / ^ [^ (] * [(] // ” | sed -e ” s / [)]. * $ // ”
  • Para resolver algo em minha rede doméstica, como myhostname.local, isso funciona para para mim, esta é a melhor resposta.
  • Posso sugerir também: ping -q -c 1 -t 1 bahface.local | grep -m 1 PING | cut -d "(" -f2 | cut -d ")" -f1
  • getent <ahosts|ahostsv4|ahostsv6|hosts> <hostname> trabalha para declarações dentro de /etc/hosts, também … e ‘ é a ferramenta go-to- para todos os tipos de bancos de dados do sistema (passwd, grupo, aliases, serviços).

Resposta

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 um CNAME, ele também obterá o IP nesse caso.

O primeiro comando retorna o endereço IPv4 resolvido.

O segundo comando retorna o res endereço IPv6 resolvido.

O terceiro comando retornará o endereço preferencial do proprietário, que pode ser um endereço IPv4 ou IPv6.

Comentários

  • De longe o mais simples. E está disponível por padrão. Diferente de host que exige a instalação do bindutils

Resposta

Aqui está uma ligeira variação da abordagem ping que leva “host desconhecido” em consideração (por piping através de 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}" 

No caso é importante capturar o valor de saída, então 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}" 

Comentários

  • Eu amo essa solução, porque ela funciona sem nenhuma ferramenta extra.

Resposta

Para completar 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 de 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 tring vazio se não for resolvido. with version of dig:

 $ dig -v DiG 9.8.1-P1 

Comentários

  • Obrigado, outras respostas pressupõem que ” dig + short ” sempre retorna um único endereço IP. Eles não ‘ t contabilizando CNAMEs.

Resposta

 php -r "echo gethostbyname("unix.stackexchange.com");" 

Comentários

  • isso funciona, mas requer que o php esteja instalado em seu terminal
  • pode ser útil em um contêiner docker php típico onde ” host “, ” dig ” etc. não estão disponíveis

Resposta

Eu gostaria de adicionar isso como um comentário para Andrew McGregor Re: ping. No entanto, não permitiu, então preciso adicionar isso como outra resposta. (Se alguém puder movê-lo para um comentário, fique à vontade para fazer isso.)

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 retorna apenas a parte correspondente. o regexp em si procura um ou vários dígitos ([0-9]+) e, opcionalmente, um ponto (\.?) quatro vezes ( {4})

Resposta

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 

Resposta

aqui “uma receita Bash Eu me preparei usando as respostas de outras pessoas – primeiro tenta /etc/hosts, 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 }  

Comentários

  • Para ser claro, getent hosts isn ‘ t apenas uma pesquisa em / etc / hosts – é ‘ uma chamada de resolução DNS completa para gethostbyaddr (3) , e ‘ é muito improvável de falhar em um caso em que dig terá sucesso. Consulte a página de manual de getent .
  • @Stuart está certo – eu ‘ aprendi muito desde que escrevi isso e simplificou demais um comando poderoso. getent continua sendo meu favorito, embora eu também goste de dig +short

Resposta

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

Resposta

Talvez não 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 gerará um único IPv4 IP, 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ê quiser um endereço IPv6, basta substituir -4 por -6.

Resposta

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

Comentários

  • Algum contexto de como essa resposta melhora em relação às já existentes seja grande. Além disso, indente os comandos em 4 espaços (cf. a sintaxe de redução).

Resposta

dig também lento, nslookup é muito mais rápido

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

Resposta

1 linha resolve uma lista do nome do host

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

Resposta

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 instalou o Node.js para fornecer uma CLI:

$ npm install -g lookup-hostname $ lookup google.com 62.243.192.89 

Comentários

  • 60% de chance de quebra antes de chegar perto de uma resolução.
  • @dotbit você poderia explicar? Eu ‘ uso isso semanalmente desde ‘ 17 e nunca tive problemas.
  • @Jensen, mas você ‘ re o único de sempre, como sempre. O resto de nós geralmente encontra FALHAS de um tipo ou de outro, e sempre.
  • ” como sempre ” O que você quer dizer com isso? ” O resto de nós ” Quem ‘ é que ? ” falha em ” Que problema específico você está vendo? Eu ‘ estou curioso.

Resposta

Eu não ” Não conheço 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 

Irá 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 

Comentários

  • usar ping é bom, porque todo mundo tem, mas você precisa filtre a IP-Part das saídas, se quiser usá-la em um script.

Resposta

Sim, já existem muitas respostas, mas uma solução usando perl está faltando:

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

Em um script bash, ele 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 instalar com o CPAN.

Comentários

  • perl -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' unix.stackexchange.com 2>/dev/null é muito mais limpo. mas ninguém além de nós dois está usando p ö rl, todos os outros usam Pascal Script, é claro.
  • Na verdade, eu prefiro ver as mensagens de erro, se houver alguma dá errado. Can't call method "addr" on an undefined value isn ‘ é exatamente a melhor mensagem de erro, mas pode dar uma dica sobre o problema.

Resposta

#!/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! " 

Comentários

  • A versão ruby imprime aspas em torno do endereço IP — provavelmente print deve ser usado em vez de p.
  • thx, @Slaven Rezic e fique à vontade para votar positivamente. então, novamente, aqui na parte inferior o script pode ser mais visível na verdade … 😉

Resposta

host -t a cisco.com 

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

Resposta

Além da solução acima, você pode traduzir vários nomes de host para ip por meio do script abaixo, a única dependência é o comando “ping” no núcleo do Unix:

getip(){ ping -c 1 -t 1 $1 | head -1 | cut -d " " -f 3 | tr -d "()" 2>&1 | tee >> /tmp/result.log & } getip "hostname.number1.net" getip "hostname.number2.net" getip "hostname.number3.net" getip "hostname.number4.net" getip "hostname.number5.net" getip "hostname.number6.net" getip "hostname.number7.net" getip "hostname.number8.net" 
$ cat /tmp/result.log ABC.DEF.GHI.XY1 ABC.DEF.GHI.XY2 ABC.DEF.GHI.XY3 ABC.DEF.GHI.XY4 ABC.DEF.GHI.XY5 ABC.DEF.GHI.XY6 ABC.DEF.GHI.XY7 ABC.DEF.GHI.XY8 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *