it-swarm-ru.tech

Как я могу разрешить имя хоста в IP-адрес в сценарии Bash?

Какой самый краткий способ преобразовать имя хоста в IP-адрес в скрипте Bash? Я использую Arch Linux .

450
Eugene Yarmash

Вы можете использовать getent, который поставляется с glibc (так что вы почти наверняка имеете его в Linux). Это решается с помощью gethostbyaddr/gethostbyname2, и поэтому также будет проверять /etc/hosts/NIS/и т.д.:

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

Или, как сказал Хайнци ниже, вы можете использовать Dig с +short аргумент (запрашивает DNS-серверы напрямую, не смотрит на /etc/hosts/NSS/etc):

Dig +short unix.stackexchange.com

Если Dig +short недоступно, любое из следующего должно работать. Все они напрямую запрашивают DNS и игнорируют другие средства разрешения:

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

Если вы хотите напечатать только один IP-адрес, добавьте команду exit в рабочий процесс 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

С Host из пакета dnsutils :

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

( Исправлено имя пакета в соответствии с комментариями. Как примечание, другие дистрибутивы имеют Host в разных пакетах: Debian/Ubuntu bind9-Host, openSUSE bind-utils, Frugalware bind.)

146
manatwork

У меня есть инструмент на моей машине, который, кажется, делает эту работу. Страница man показывает, что, похоже, она поставляется с mysql ... Вот как вы можете ее использовать:

resolveip -s unix.stackexchange.com
64.34.119.12

Возвращаемое значение этого инструмента отличается от 0, если имя хоста не может быть разрешено:

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

UPDATE В Fedora поставляется с mysql-сервером:

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

Я думаю, это создаст странную зависимость для вашего сценария ...

56
greg0ire

Следующая команда, использующая Dig, позволяет вам читать результат напрямую без sed/awk/etc. магия:

$ Dig +short unix.stackexchange.com
64.34.119.12

Dig также входит в пакет dnsutils.


Примечание: Dig имеет возвращаемое значение 0, даже если имя не может быть разрешено. Таким образом, вам нужно проверить, пустой ли вывод, вместо проверки возвращаемого значения:

hostname=unix.stackexchange.com

ip=`Dig +short $hostname`

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

Примечание 2: если имя хоста имеет несколько IP-адресов (попробуйте debian.org, например), все они будут возвращены. Эта "проблема" затрагивает все инструменты, упомянутые в этом вопросе:

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

Представленные решения в основном работают в более простом случае: имя хоста напрямую разрешается в один IPv4-адрес. Это может быть единственный случай, когда вам нужно разрешить имена хостов, но если нет, то ниже приводится обсуждение некоторых случаев, которые вам, возможно, придется обработать.

Крис Даун и Хайнци кратко обсудили случай, когда имя хоста разрешается для более чем одного IP-адреса. В этом случае (и других ниже) базовые сценарии в предположении, что имя хоста напрямую разрешает один IP-адрес, могут сломаться. Ниже приведен пример разрешения имени хоста более чем на один 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

Но что такое www.l.google.com? Здесь необходимо ввести случай псевдонима . Давайте проверим пример ниже:

$ 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

Так www.google.com не разрешается напрямую по IP-адресам, а по псевдониму, который сам по себе разрешается по нескольким IP-адресам. Для получения дополнительной информации о псевдонимах, проверьте здесь . Конечно, возможен случай, когда псевдоним имеет один IP-адрес, как показано ниже:

$ 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

Но можно ли связывать псевдонимы? Ответ да:

$ 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

Я не нашел ни одного примера, где имя хоста преобразуется в псевдоним, который не преобразуется в IP-адрес, но я думаю, что это может произойти.

Больше, чем несколько IP-адресов и псевдонимов, есть ли другие особые случаи ... как насчет IPv6? Вы можете попробовать:

$ 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

Где имя хоста ipv6.google.com - это имя хоста только для IPv6. А как насчет имен хостов с двумя стеками:

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

Опять же, что касается IPv6, если ваш хост - только IPv4, вы все равно можете разрешать адреса IPv6 (протестировано только на WinXP только для IPv4, а на ipv6.google.com вы можете попробовать его в Linux). В этом случае разрешение завершается успешно, но проверка связи не выполняется с неизвестное сообщение об ошибке хоста. Это может быть случай, когда ваш сценарий не работает.

Я надеюсь, что эти замечания были полезны.

30
jfg956

Чтобы избежать проблемы с псевдонимами и всегда получать один IP-адрес, готовый к использованию:

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

Просто, но полезно:

  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

Все команды разрешают IP-адрес, если хост все еще существует. Если Хост указывает на CNAME, он также получит IP-адрес в этом случае.

Первая команда возвращает разрешенный адрес IPv4

Вторая команда возвращает разрешенный адрес IPv6

Третья команда вернет владельцу предпочтительный адрес, который может быть IPv4 или IPv6.

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

работает без зависимостей в других системах (и для хостов, указанных в/etc/hosts)

19
Andrew McGregor

Вот небольшой вариант подхода ping, который учитывает "неизвестный хост" (путем передачи через stderr) и использует tr, чтобы избежать использования sed regexps:

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

В случае, если важно получить выходное значение, будет работать следующее (хотя и менее изящное):

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

Чтобы завершить ответ Криса Дауна и обратиться к комментариям jfgagne относительно (возможно, связанных) псевдонимов, вот решение, которое:

  • учитывает несколько IP-адресов
  • учитывает один или несколько псевдонимов (CNAME)
  • не запрашивает /etc/hosts файл (в моем случае я этого не хотел); чтобы запросить его, dbernt's python идеально)
  • не использует awk/sed

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

Всегда возвращает первый IP-адрес или пустую строку, если не решен. с версией Dig:

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

Я хотел бы добавить это как комментарий к Эндрю МакГрегору Re: ping. Однако это не позволило бы мне, поэтому мне нужно добавить это в качестве другого ответа. (Если кто-то может переместить это в комментарий, не стесняйтесь.)

Это еще один вариант, только с использованием ping и grep:

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

grep -E для расширенного регулярного выражения и grep -o чтобы вернуть только соответствующую часть. само регулярное выражение ищет одну или несколько цифр ([0-9]+) и необязательно точка (\.?) четыре раза ({4})

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

было решение, которое я нашел без DNS-сервера

5
Philippe Gachoud

вот рецепт Bash, который я приготовил, используя ответы других людей - сначала пробует /etc/hosts, затем возвращается к 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

Вы можете использовать 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

Может быть, не самый краткий, но он кажется надежным и эффективным:

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

Это выведет один IPv4 IP, а также вернет 1 в случае сбоя при маскировке вывода stderr.

Вы можете использовать это так:

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

IP-адрес Google - 216.58.192.46.

Если вы хотите вместо этого адрес IPv6, просто замените -4 с -6.

4
Will

Копать слишком медленно, nslookup намного быстрее

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 строка разрешает список имен хостов

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

Я не знаю самого простого способа для bash-скрипта, но если вы хотите определить имя хоста и посмотреть, работает ли хост, используйте ping!

ping -a hostname -c 1

Будет ping Хостом один раз и преобразует имя хоста в 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

Я делаю это все время на моем Mac, на котором нет getent. ping похоже на хак. Я хотел бы взять /etc/hosts также во внимание.

Итак, я написал глупую оболочку для dns.lookup для тех, у кого установлен Node.js для предоставления 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

Да, ответов уже много, но решение с использованием Perl отсутствует:

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

В скрипте bash это можно использовать так:

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

Модули, используемые здесь, являются основными модулями, поэтому должны быть доступны везде без установки с CPAN.

2
Slaven Rezic