tra-loi-cau-hoi-phat-trien-web.com

Làm cách nào tôi có thể phân giải tên máy chủ thành địa chỉ IP trong tập lệnh Bash?

Cách ngắn gọn nhất để phân giải tên máy chủ thành địa chỉ IP trong tập lệnh Bash là gì? Tôi đang sử dụng Arch Linux .

450
Eugene Yarmash

Bạn có thể sử dụng getent, đi kèm với glibc (vì vậy bạn gần như chắc chắn có nó trên Linux). Điều này giải quyết bằng cách sử dụng gethostbyaddr/gethostbyname2 và do đó cũng sẽ kiểm tra /etc/hosts/NIS/v.v:

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

Hoặc, như Heinzi đã nói bên dưới, bạn có thể sử dụng Dig với +short đối số (truy vấn máy chủ DNS trực tiếp, không nhìn vào /etc/hosts/NSS/v.v.):

Dig +short unix.stackexchange.com

Nếu Dig +short không có sẵn, bất kỳ một trong những điều sau đây sẽ hoạt động. Tất cả các truy vấn DNS trực tiếp và bỏ qua các phương tiện giải quyết khác:

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

Nếu bạn muốn chỉ in một IP, sau đó thêm lệnh exit vào quy trình làm việc của 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

Với Host từ gói dnsutils :

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

( Tên gói đã sửa theo nhận xét. Như một lưu ý, các bản phân phối khác có Host trong các gói khác nhau: Debian/Ubuntu bind9-Host, openSUSE bind-utils, Frrifware bind.)

146
manatwork

Tôi có một công cụ trên máy của tôi dường như thực hiện công việc. Trang người đàn ông cho thấy nó dường như đi kèm với mysql ... Đây là cách bạn có thể sử dụng nó:

resolveip -s unix.stackexchange.com
64.34.119.12

Giá trị trả về của công cụ này khác 0 nếu tên máy chủ không thể được giải quyết:

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

UPDATE Trên Fedora, nó đi kèm với máy chủ 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

Tôi đoán nó sẽ tạo ra một sự phụ thuộc kỳ lạ cho kịch bản của bạn ...

56
greg0ire

Lệnh sau sử dụng Dig cho phép bạn đọc kết quả trực tiếp mà không cần bất kỳ sed/awk/etc. ma thuật:

$ Dig +short unix.stackexchange.com
64.34.119.12

Dig cũng được bao gồm trong gói dnsutils.


Lưu ý: Dig có giá trị trả về là 0, ngay cả khi tên không thể được giải quyết. Do đó, bạn cần kiểm tra xem đầu ra có trống không thay vì kiểm tra giá trị trả về:

hostname=unix.stackexchange.com

ip=`Dig +short $hostname`

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

Lưu ý 2: Nếu tên máy chủ có nhiều địa chỉ IP (hãy thử debian.org, ví dụ), tất cả chúng sẽ được trả lại. "Vấn đề" này ảnh hưởng đến tất cả các công cụ được đề cập trong câu hỏi này cho đến nay:

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

Các giải pháp được đưa ra cho đến nay hầu hết đều hoạt động trong trường hợp đơn giản hơn: tên máy chủ trực tiếp phân giải thành một địa chỉ IPv4 duy nhất. Đây có thể là trường hợp duy nhất mà bạn cần giải quyết tên máy chủ, nhưng nếu không, dưới đây là một cuộc thảo luận về một số trường hợp mà bạn có thể cần phải xử lý.

Chris Down và Heinzi đã thảo luận ngắn gọn về trường hợp tên máy chủ giải quyết thành nhiều hơn một địa chỉ IP. Trong trường hợp này (và những người khác bên dưới), tập lệnh cơ bản theo giả định rằng tên máy chủ trực tiếp phân giải thành một địa chỉ IP duy nhất có thể bị hỏng. Dưới đây, một ví dụ với tên máy chủ phân giải thành nhiều hơn một địa chỉ 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

Nhưng cái gì là www.l.google.com? Đây là nơi cần phải giới thiệu trường hợp bí danh . Hãy xem ví dụ dưới đây:

$ 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

Vì thế www.google.com không trực tiếp phân giải thành các địa chỉ IP, nhưng với một bí danh mà chính nó phân giải thành nhiều địa chỉ IP. Để biết thêm thông tin về bí danh, hãy kiểm tra tại đây . Tất nhiên, trường hợp bí danh có một địa chỉ IP duy nhất là có thể, như được hiển thị bên dưới:

$ 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

Nhưng bí danh có thể bị xiềng xích? Câu trả lời là có:

$ 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

Tôi không tìm thấy bất kỳ ví dụ nào mà tên máy chủ phân giải thành bí danh không phân giải địa chỉ IP, nhưng tôi nghĩ trường hợp này có thể xảy ra.

Hơn nhiều địa chỉ IP và bí danh, có một số trường hợp đặc biệt khác ... còn IPv6 thì sao? Bạn có thể thử:

$ 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

Tên máy chủ ipv6.google.com là tên máy chủ chỉ IPv6. Những gì về tên máy chủ ngăn xếp kép:

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

Một lần nữa về IPv6, nếu Máy chủ của bạn chỉ là IPv4, bạn vẫn có thể giải quyết các địa chỉ IPv6 (chỉ được thử nghiệm trên IPv4 WinXP và với ipv6.google.com, bạn có thể dùng thử trên Linux). Trong trường hợp này, độ phân giải thành công, nhưng ping không thành công với một thông báo lỗi Máy chủ không xác định. Đây có thể là một trường hợp mà kịch bản của bạn thất bại.

Tôi hy vọng những nhận xét đó là hữu ích.

30
jfg956

Để tránh sự cố với bí danh và luôn có sẵn một địa chỉ IP duy nhất để sử dụng:

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

Đơn giản nhưng hữu ích:

  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

Tất cả các lệnh sẽ giải quyết một địa chỉ IP nếu Máy chủ vẫn tồn tại. Nếu Máy chủ trỏ đến CNAME, nó cũng sẽ nhận được IP trong trường hợp đó.

Lệnh đầu tiên trả về địa chỉ IPv4 đã giải quyết

Lệnh thứ hai trả về địa chỉ IPv6 đã giải quyết

Lệnh thứ ba sẽ trả về địa chỉ ưa thích của chủ sở hữu địa chỉ IPv4 hoặc IPv6.

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

hoạt động mà không phụ thuộc vào các hệ thống khác (và cho các máy chủ được chỉ định trong/etc/hosts)

19
Andrew McGregor

Đây là một biến thể nhỏ của cách tiếp cận ping đưa "Máy chủ không xác định" vào tài khoản (bằng cách chuyển qua stderr) và sử dụng tr để tránh sử dụng sed regexps:

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

Trong trường hợp điều quan trọng là phải nắm bắt giá trị thoát, thì cách sau sẽ hoạt động (mặc dù kém thanh lịch):

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

Để hoàn thành câu trả lời của Chris Down và giải quyết các bình luận của jfgagne về các bí danh (có thể bị xiềng xích), đây là một giải pháp:

  • đưa vào tài khoản nhiều IP
  • tính đến một hoặc nhiều bí danh (CNAME)
  • không truy vấn /etc/hosts file (trong trường hợp của tôi, tôi không muốn nó); để truy vấn nó, giải pháp của dbernt's python là hoàn hảo)
  • không sử dụng awk/sed

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

Luôn trả về địa chỉ IP đầu tiên hoặc tring trống nếu không được giải quyết. với phiên bản của Dig:

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

Tôi muốn thêm điều này như một bình luận cho Andrew McGregor Re: ping. Tuy nhiên nó sẽ không cho phép tôi, vì vậy tôi cần thêm câu này như một câu trả lời khác. (Nếu ai đó có thể chuyển nó thành một nhận xét, vui lòng.)

Đây là một biến thể khác, chỉ sử dụng ping và grep:

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

grep -E cho biểu thức chính quy mở rộng và grep -o để chỉ trả lại phần phù hợp. regrec chính nó tìm kiếm một hoặc nhiều chữ số ([0-9]+) và tùy ý là một dấu chấm (\.?) bốn lần ({4})

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

là giải pháp tôi tìm thấy mà không cần máy chủ DNS

5
Philippe Gachoud

đây là một công thức Bash tôi đã nấu lên bằng cách sử dụng các câu trả lời của dân gian khác - lần đầu tiên thử /etc/hosts, sau đó rơi trở lại 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

Bạn có thể sử dụng 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

Có thể không phải là ngắn gọn nhất, nhưng nó có vẻ mạnh mẽ và hiệu quả:

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

Điều này sẽ xuất ra một IP IPv4 duy nhất, cũng như trả về 1 trong trường hợp thất bại, trong khi che dấu đầu ra stderr.

Bạn có thể sử dụng nó như thế này:

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 của Google là 216.58.192.46.

Nếu bạn muốn một địa chỉ IPv6 thay thế, chỉ cần thay thế -4 với -6.

4
Will

Dig quá chậm, nslookup nhanh hơn nhiều

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 dòng giải quyết một danh sách tên máy chủ

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

Tôi không biết cách dễ nhất cho bash-script nhưng nếu bạn muốn giải quyết tên máy chủ và xem liệu Host có hoạt động hay không, hãy sử dụng ping!

ping -a hostname -c 1

Sẽ ping Máy chủ lưu trữ một lần và giải quyết tên máy chủ thành địa chỉ 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

Tôi đang làm điều này mọi lúc trên máy Mac không có getent. ping có vẻ như là một hack. Tôi muốn lấy /etc/hosts vào tài khoản là tốt.

Vì vậy, tôi đã viết một trình bao bọc ngu ngốc cho dns.lookup cho bạn đã cài đặt Node.js để cung cấp 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

Có, đã có nhiều câu trả lời, nhưng thiếu một giải pháp sử dụng Perl:

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

Trong một tập lệnh bash, nó có thể được sử dụng như thế này:

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

Các mô-đun được sử dụng ở đây là các mô-đun cốt lõi, do đó nên có sẵn ở mọi nơi mà không cần cài đặt với CPAN.

2
Slaven Rezic