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

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

312 голосов | спросил Eugene Yarmash 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 15 Sep 2011 18:43:48 +0400 2011, 18:43:48

22 ответа


399

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

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 }'
ответил Chris Down 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 15 Sep 2011 20:29:41 +0400 2011, 20:29:41
123

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

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

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

ответил manatwork 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 15 Sep 2011 18:50:57 +0400 2011, 18:50:57
44

У меня есть инструмент на моей машине, который, похоже, выполняет эту работу. На странице 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

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

ответил greg0ire 16 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 16 Sep 2011 01:50:00 +0400 2011, 01:50:00
35

Следующая команда, использующая 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), все они будут возвращены. Эта «проблема» затрагивает все инструменты, упомянутые в этом вопросе:

ответил Heinzi 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 15 Sep 2011 22:23:53 +0400 2011, 22:23:53
30
getent hosts unix.stackexchange.com | cut -d' ' -f1
ответил sborsky 4 +04002013-10-04T23:12:16+04:00312013bEurope/MoscowFri, 04 Oct 2013 23:12:16 +0400 2013, 23:12:16
22

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

Chris Down и Heinzi кратко обсудили случай, когда имя хоста решает несколько 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-only. Что можно сказать о именах с двумя стеками:

$ 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-адреса (протестированные только на IPv4 только WinXP и с ipv6.google.com, вы можете попробовать его в Linux). В этом случае разрешение преуспевает, но ping завершается с сообщением об ошибке unknown host . Это может быть случай, когда ваш скрипт терпит неудачу.

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

ответил jfg956 21 stEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 21 Sep 2011 19:13:13 +0400 2011, 19:13:13
16

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

python -c 'import socket; print socket.gethostbyname("www.example.com")'
ответил dbernt 12 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 12 Sep 2012 13:34:40 +0400 2012, 13:34:40
13
ping -q -c 1 -t 1 your_host_here | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"

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

ответил Andrew McGregor 11 AM00000010000004331 2012, 01:20:43
13

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

  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-адрес.

ответил Tom Freudenberg 15 J0000006Europe/Moscow 2014, 18:42:25
3

Вы можете использовать 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
ответил Matteo 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 15 Sep 2011 19:01:37 +0400 2011, 19:01:37
3

Ниже приведен небольшой вариант подхода 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}'
ответил Stefan Farestam 4 +04002013-10-04T19:22:19+04:00312013bEurope/MoscowFri, 04 Oct 2013 19:22:19 +0400 2013, 19:22:19
3

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

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

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

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

    $ dig -v
    DiG 9.8.1-P1
ответил Franck 30 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 30 Sep 2014 19:26:23 +0400 2014, 19:26:23
2
nmap -sP 192.168.178.0/24|grep YOUR_HOSTNAME|sed -n 's/.*[(]\([0-9\.]*\)[)].*/\1/p'

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

ответил Philippe Gachoud 14 PM00000060000005431 2015, 18:07:54
1

вот рецепт 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
}
ответил RubyTuesdayDONO 11 Jam1000000amSat, 11 Jan 2014 05:16:59 +040014 2014, 05:16:59
1
 php -r "echo gethostbyname('unix.stackexchange.com');"
ответил Mohammed Zourob 30 AMpThu, 30 Apr 2015 01:01:20 +030001Thursday 2015, 01:01:20
1

Возможно, не самый сжатый, но он кажется надежным и эффективным:

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

ответил Will 4 PM000000100000001931 2015, 22:47:19
1

Я бы хотел добавить это как комментарий к Andrew McGregor Re: ping. Однако это не позволило мне, поэтому мне нужно добавить это как еще один ответ. (Если кто-то может переместить это в комментарий, не стесняйтесь.)

Это другой вариант, только используя ping и grep:

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

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

ответил Dweia 3 42016vEurope/Moscow11bEurope/MoscowThu, 03 Nov 2016 20:31:16 +0300 2016, 20:31:16
0

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

ответил D P Baker 18 MaramFri, 18 Mar 2016 00:03:08 +03002016-03-18T00:03:08+03:0012 2016, 00:03:08
0

1 строка разрешает список имен хостов

for LINE in `cat ~/Desktop/mylist`; do a=$(nslookup $LINE | awk '/^Address: / { print $1 }');  echo $a >> ~/Desktop/ip; done
ответил Andy Wong 23 MarpmThu, 23 Mar 2017 12:59:02 +03002017-03-23T12:59:02+03:0012 2017, 12:59:02
0

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

Итак, я написал глупую оболочку для dns.lookup для тех, у кого установлен Node.js для предоставления CLI:

$ npm install -g lookup-hostname
$ lookup google.com
62.243.192.89
ответил Thomas Jensen 14 Mayam17 2017, 03:16:32
0

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

nslookup google.com | grep -Po 'Address:\s*[0-9.]+' | tail -1 | sed -e 's/Address:\s*//g'
ответил Andrey Izman 14 22017vEurope/Moscow11bEurope/MoscowTue, 14 Nov 2017 06:40:23 +0300 2017, 06:40:23
0

Я не знаю самый простой способ для 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
ответил user257655 27 +03002017-10-27T09:12:04+03:00312017bEurope/MoscowFri, 27 Oct 2017 09:12:04 +0300 2017, 09:12:04

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132