Làm cách nào tôi có thể nhận địa chỉ IP của riêng mình và lưu nó vào một biến trong tập lệnh shell?
Làm cách nào tôi có thể nhận địa chỉ IP của riêng mình và lưu nó vào một biến trong tập lệnh shell?
Câu trả lời:
Thật không dễ dàng nếu bạn muốn tính đến wlan và các giao diện thay thế khác. Nếu bạn biết giao diện nào bạn muốn địa chỉ cho (ví dụ: eth0, thẻ Ethernet đầu tiên), bạn có thể sử dụng giao diện này:
ip="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
Nói cách khác, hãy cho tôi thông tin cấu hình mạng, tìm kiếm eth0
, lấy dòng đó và dòng tiếp theo ( -A 1
), chỉ lấy dòng cuối cùng, lấy phần thứ hai của dòng đó khi chia tách :
, sau đó lấy phần đầu tiên khi chia tách với không gian.
grep
vào mã của bạn để bỏ qua bất kỳ giao diện nào có "eth0:" trong đó; bây giờ nó hoạt động như tôi mong đợi (chỉ cung cấp địa chỉ IP "eth0" chứ không phải bất kỳ giao diện phụ nào (eth0: 0, eth0: 1, v.v.):ip="$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
ifconfig eth0
ip address
thay vào đó bạn nên sử dụng
Tôi tin rằng cách "công cụ hiện đại" để lấy địa chỉ ipv4 của bạn là phân tích 'ip' thay vì 'ifconfig', vì vậy nó sẽ giống như:
ip4=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
ip6=$(/sbin/ip -o -6 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
hoặc điều tương tự.
ip
có sẵn trên tất cả các bản phân phối Red Hat và Fedora mà tôi đã sử dụng. ip
là một phần của gói iproute2 ( linuxfoundation.org/collabISE/workgroups/networking/iproute2 ). ifconfig
và route
được cho là không dùng nữa, mặc dù chúng tiếp tục được sử dụng bởi rất nhiều người, đặc biệt là trong các kịch bản. ip
là nhiều phân tích hơn, trong ý kiến của tôi.
ip
cũng có sẵn trên tất cả các bản phân phối dựa trên Debian và Debian mà tôi đã thấy. Đây là một phần của gói iproute được đánh dấu là quan trọng.
ip
là một phần của gói iproute2 theo mặc định là một bản phân phối. Đó là trong hầu hết các repos tốt. vi.wikipedia.org/wiki/Iproute2
/sbin/ip
thay vì ip
?
awk
và cut
gây cười cho tôi, đây là một sự thay thế khả dĩ có thể không thực sự tốt hơn:ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
Tại sao không đơn giản làm IP=$(hostname -I)
?
hostname -i
chỉ cho tôi 127.0.0.1
, hostname -I
cho tôi địa chỉ IP chính xác ...
-i Display the network address(es) of the host name. Note that this works only if the host name can be resolved. Avoid using this option; use hostname --all-ip-addresses
/etc/hosts
, cùng với địa chỉ IP tương ứng
-I
trên FreeBSD, nhưng bạn có thể sử dụngdig +short `hostname -f`
Nếu bạn muốn địa chỉ của một giao diện, cách dễ nhất là cài đặt thêmututils sau đó:
anthony@Zia:~$ ifdata -pa br0
172.16.1.244
ifdata
trả lời khá nhiều câu hỏi mà bạn muốn phân tích ifconfig
đầu ra cho.
Nếu bạn muốn tìm ra địa chỉ IP của mình khi bên ngoài nhìn thấy địa chỉ đó (ngoài bất kỳ NAT nào, v.v.), có rất nhiều dịch vụ sẽ làm điều đó. Một là khá dễ dàng:
anthony@Zia:~$ curl ifconfig.me
173.167.51.137
ifdata
thêm vào iproute2
. Có thể một nhị phân mới được gọi làipdata
Để nhận địa chỉ IPv4 và IPv6 và không giả sử giao diện chính là eth0
(ngày nay em1
phổ biến hơn ), hãy thử:
ips=$(ip -o addr show up primary scope global |
while read -r num dev fam addr rest; do echo ${addr%/*}; done)
-o
sử dụng định dạng đầu ra một dòng, đó là dễ dàng hơn để xử lý với read
, grep
vvup
loại trừ các thiết bị không hoạt độngscope global
không bao gồm các địa chỉ riêng tư / địa phương như 127.0.0.1
vàfe80::/64
primary
loại trừ các địa chỉ tạm thời (giả sử bạn muốn một địa chỉ không thay đổi)-4
/ -6
để lọc các loại địa chỉ. Bạn cũng có thể dễ dàng nhận được các thông số giao diện khác. Cá nhân, tôi không thích vòng lặp while và tôi thíchgrep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
Phụ thuộc vào ý nghĩa của bạn bằng địa chỉ IP của chính bạn. Các hệ thống có địa chỉ IP trên một số mạng con (đôi khi là một vài mạng con), một số trong đó có IPv4, một số IPv6 sử dụng các thiết bị như bộ điều hợp ethernet, giao diện loopback, đường hầm VPN, cầu nối, giao diện ảo ...
Ý tôi là địa chỉ IP mà một thiết bị cụ thể khác có thể truy cập vào máy tính của bạn, bạn phải tìm ra mạng con nào và phiên bản IP nào chúng ta đang nói đến. Ngoài ra, hãy nhớ rằng do NAT được thực hiện bởi tường lửa / bộ định tuyến, địa chỉ IP của giao diện có thể không giống như máy chủ từ xa nhìn thấy kết nối đến từ máy tính của bạn đến từ.
Khi có định tuyến nguồn ưa thích hoặc định tuyến theo giao thức / cổng, có thể khó tìm ra giao diện nào sẽ được sử dụng để nói chuyện với một máy tính từ xa qua một giao thức nhất định và thậm chí sau đó, không có gì đảm bảo rằng địa chỉ IP của giao diện đó có thể địa chỉ trực tiếp bởi máy tính từ xa muốn thiết lập kết nối mới với máy tính của bạn.
Đối với IPv4 (có thể cũng hoạt động với IPv6), một mẹo hoạt động trong nhiều đơn vị bao gồm cả Linux để tìm ra địa chỉ IP của giao diện được sử dụng để truy cập một máy chủ nhất định là sử dụng kết nối (2) trên ổ cắm UDP và sử dụng tên khóa ():
Ví dụ, trên máy tính ở nhà của tôi:
perl -MSocket -le 'socket(S, PF_INET, SOCK_DGRAM, getprotobyname("udp"));
connect(S, sockaddr_in(1, inet_aton("8.8.8.8")));
print inet_ntoa((sockaddr_in(getsockname(S)))[1]);'
Sẽ được sử dụng để tìm ra địa chỉ IP của giao diện mà qua đó tôi sẽ đạt đến 8.8.8.8 (máy chủ DNS của google). Nó sẽ trả về một cái gì đó như "192.168.1.123" là địa chỉ của giao diện cho tuyến đường mặc định tới internet. Tuy nhiên, google sẽ không thấy yêu cầu DNS từ máy của tôi đến từ địa chỉ IP đó là địa chỉ riêng tư, vì có NAT được thực hiện bởi bộ định tuyến băng thông rộng tại nhà của tôi.
kết nối () trên ổ cắm UDP không gửi bất kỳ gói tin nào (UDP không có kết nối), nhưng chuẩn bị ổ cắm bằng cách truy vấn bảng định tuyến.
ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')
ipa=$(hostname -i|cut -f2 -d ' ')
-I
thay vì -i
tốt hơn là bạn muốn bỏ qua các địa chỉ loopback, vì vậy lệnh cuối cùng sẽ làipa=$(hostname -I|cut -f1 -d ' ')
grep
không đủ, đừng chuyển nó sang thứ khác. Chỉ cần sử dụng cái gì khác ( sed
, awk
, vv).
Tôi không có ý là một thằng ngốc, nhưng thực sự có một cách đúng đắn và đây là nó. Bạn cắt đầu ra của ip route
để chỉ lấy IP nguồn. Tùy thuộc vào IP nào bạn đang cố truy cập, "địa chỉ IP của riêng tôi" (từ của OP) sẽ khác nhau. Nếu bạn quan tâm đến việc truy cập internet công cộng, sử dụng máy chủ DNS 8.8.8.8 của Google là khá chuẩn. Vì thế...
ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
Nếu tôi muốn ip tôi sử dụng để truy cập internet , tôi sử dụng:
pi@et3:~ $ ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
10.55.0.200
Nếu tôi muốn ip tôi sử dụng để đạt được thứ gì đó trên VPN của mình , tôi sử dụng cái này:
pi@et3:~ $ ip route get 172.31.0.100 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
172.29.0.9
Điều tiếp theo này thực sự chỉ nhằm mục đích minh họa. Nhưng, nó nên hoạt động trên mọi hệ thống Linux. Vì vậy, bạn có thể sử dụng điều này để chứng minh rằng, vâng, tất cả các máy đều có nhiều địa chỉ IP mọi lúc.
Nếu tôi muốn ip tôi sử dụng để tiếp cận bản thân , tôi sẽ sử dụng cái này:
pi@et3:~ $ my_ip=$(getent hosts $(cat /etc/hostname) | awk '{print $1; exit}')
pi@et3:~ $ ip route get $my_ip | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
127.0.0.1
sed
lệnhTrước tiên hãy để tôi nói rằng khi chọn các công cụ unix, bạn cố gắng chọn các công cụ yêu cầu ít đường ống nhất. Vì vậy, trong khi một số câu trả lời sẽ ống ifconfig
để grep
đến sed
đến head
, đó là hiếm khi cần thiết. Khi bạn nhìn thấy nó, nó sẽ giơ một lá cờ đỏ mà bạn đang nhận lời khuyên từ một người có ít kinh nghiệm. Điều đó không làm cho "giải pháp" sai. Nhưng, nó có thể có thể sử dụng một số tinh giản.
Tôi đã chọn sed
vì nó ngắn gọn hơn so với quy trình làm việc tương tự awk
. (Tôi có từ một ví dụ awk bên dưới.) Tôi không nghĩ bất kỳ công cụ nào khác nhưng 2 công cụ đó sẽ phù hợp.
Hãy xem xét những gì sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
:
sed # the sed executable located via $PATH
-n # no output unless explicitly requested
' # begin the command space
/src/ # regex match the string 'src'
{ # begin a block of commands **
s/ # begin a substitution (match)
.*src * # match anything leading up to and including src and any number of spaces
\([^ ]*\) # define a group containing any number of non spaces
.* # match any trailing characters (which will begin with a space because of the previous rule).
/ # begin the substitution replacement
\1 # reference the content in the first defined group
/ # end the substitution
p # print (explicitly, remember) the result
; # designate the end of the command
q # quit
} # end the block of commands
' # end the command space
** all of which will be performed "on match"
- otherwise only the first command to following the match would be performed "on match"
- any other commands would be performed whether there was a match or not
Ghi chú:
Tôi đã từng sử dụng sed -n '/src/{s/.*src *//p;q}'
nhưng một nhà bình luận chỉ ra rằng một số hệ thống có dữ liệu theo sau src
trường.
ip route get 8.8.8.8 | \
awk '{gsub(".*src",""); print $1; exit}'
# or
ip route get 8.8.8.8 | \
awk '{for(i=1; i<NF; i++){if($i=="src"){i++; print $i; exit}}}'
Của tôi ifconfig
cho thấy rằng tôi có tun0
cho VPN của tôi và eth0
cho lan của tôi.
pi@et3:~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.55.0.200 netmask 255.255.252.0 broadcast 10.55.3.255
inet6 fe80::71e6:5d7c:5b4b:fb25 prefixlen 64 scopeid 0x20<link>
ether b8:27:eb:b2:96:84 txqueuelen 1000 (Ethernet)
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500
inet 172.29.0.9 netmask 255.255.255.255 destination 172.29.0.10
inet6 fe80::3a8e:8195:b86c:c68c prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC)
wlan0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether b8:27:eb:e7:c3:d1 txqueuelen 1000 (Ethernet)
ip route get 8.8.8.8 | sed -n '/src/{s/.*src *//p;q}'
đã cho tôi 10.1.2.3 uid 1002
. Vì vậy, tôi thêm vào để chắp thêm | awk '{print $1}'
chỉ giữ địa chỉ IP.
Trên FreeBSD bạn có thể sử dụng
dig +short `hostname -f`
Điều này có thể làm việc cho các môi trường khác, tùy thuộc vào thiết lập của bạn.
/etc/resolv.conf
và cách bộ định tuyến mạng xử lý tên máy chủ cục bộ. Sử dụng nó trong môi trường của bạn là tốt nếu bạn kiểm tra nó và nó hoạt động. Nhưng nếu bạn làm như vậy, bạn đang xây dựng một hệ thống "dễ vỡ" sẽ gây ra vấn đề cho người khác nếu bạn chia sẻ điều này. Sử dụng cẩn thận.
Giả sử rằng bạn có thể có nhiều giao diện khác nhau nhưng bạn muốn giao diện không phải localhost đầu tiên và không ipv6, bạn có thể thử:
ip=`ip addr show |grep "inet " |grep -v 127.0.0. |head -1|cut -d" " -f6|cut -d/ -f1`
Tôi sử dụng một lớp lót này:
IP=$(/sbin/ifconfig | grep -e "inet:" -e "addr:" | grep -v "inet6" | grep -v "127.0.0.1" | head -n 1 | awk '{print $2}' | cut -c6-)
Sử dụng ifconfig
(có sẵn rộng rãi), không lấy localhost
địa chỉ, không ràng buộc bạn với một tên giao diện nhất định, không tính đến IPv6 và cố gắng lấy IP của giao diện mạng đầu tiên khả dụng.
Bạn nên sử dụng ip
(thay vì ifconfig
) như hiện tại, được duy trì và có lẽ quan trọng nhất cho các mục đích kịch bản, nó tạo ra một đầu ra nhất quán & có thể phân tích cú pháp. Sau đây là một vài cách tiếp cận tương tự:
Nếu bạn muốn địa chỉ IPv4 cho giao diện Ethernet của mình eth0
:
$ ip -4 -o addr show eth0 | awk '{print $4}'
192.168.1.166/24
Như một kịch bản:
$ INTFC=eth0
$ MYIPV4=$(ip -4 -o addr show $INTFC | awk '{print $4}')
$ echo $MYIPV4
192.168.1.166/24
Đầu ra được sản xuất ở trên là ký hiệu CIDR. Nếu ký hiệu CIDR không muốn, nó có thể bị xóa:
$ ip -4 -o addr show eth0 | awk '{print $4}' | cut -d "/" -f 1
192.168.1.166
Một tùy chọn khác mà IMHO là "thanh lịch nhất" lấy địa chỉ IPv4 cho bất kỳ giao diện nào được sử dụng để kết nối với máy chủ từ xa được chỉ định (trong trường hợp này là 8.8.8.8). Phép lịch sự của @gatoatigrado trong câu trả lời này :
$ ip route get 8.8.8.8 | awk '{ print $NF; exit }'
192.168.1.166
Như một kịch bản:
$ RHOST=8.8.8.8
$ MYIP=$(ip route get $RHOST | awk '{ print $NF; exit }')
$ echo $MYIP
192.168.1.166
Điều này hoạt động hoàn toàn tốt trên một máy chủ với một giao diện duy nhất, nhưng thuận lợi hơn là cũng sẽ hoạt động trên các máy chủ có nhiều giao diện và / hoặc thông số kỹ thuật tuyến đường.
ip
sẽ là cách tiếp cận ưa thích của tôi, nhưng chắc chắn đó không phải là cách duy nhất để lột da con mèo này. Đây là một cách tiếp cận khác sử dụng hostname
nếu bạn thích thứ gì đó dễ dàng / ngắn gọn hơn:
$ hostname --all-ip-addresses | awk '{print $1}'
Hoặc, nếu bạn muốn địa chỉ IPv6:
$ hostname --all-ip-addresses | awk '{print $2}'
Tôi cần phải làm điều này trong một bí danh để khởi động một máy chủ radio trên máy ảo có dây của tôi. Tôi đã sử dụng
ip addr | egrep -i "inet.+eth1" | awk -F[\ /] '{print $6}' | tr -d [:space:]
egrep
được khấu hao. Sử dụng grep -E
thay thế.
Một số lệnh đang làm việc trên centos 6 hoặc 7, lệnh dưới đây hoạt động trên cả hai,
#!/bin/sh
serverip=`/sbin/ifconfig eth0 | grep "inet" | awk '{print $2}' | awk 'NR==1' | cut -d':' -f2`
echo $serverip
grep | awk | awk
. dòng có thể được rút ngắn thành/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
Đoạn mã này tránh mã hóa cứng tên thiết bị (như 'eth0') và sẽ sử dụng ip
thay vì ifconfig
:
/sbin/ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/'
Nó sẽ trả về IP của thiết bị hoạt động đầu tiên được liệt kê trong đầu ra của ip addr
. Tùy thuộc vào máy của bạn, đây có thể là địa chỉ ipv4 hoặc ipv6.
Để lưu nó vào một biến, sử dụng:
ip=$(/sbin/ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/')
tất cả các giải pháp sử dụng awk / sed / grep dường như quá phức tạp và xấu xí đối với tình huống của tôi ... vì vậy tôi đã đưa ra giải pháp thực sự đơn giản này NHƯNG hãy cẩn thận vì nó đưa ra một số giả định, cụ thể là giả định rằng giao diện LAST là bạn quan tâm đến. nếu bạn ổn với điều đó thì điều này khá sạch sẽ:
ifconfig | awk '/net / { x = $2 } END { print x }'
nếu không, bạn có thể thực hiện một số if
tuyên bố ngớ ngẩn để kiểm tra tiền tố cụ thể hoặc bất kỳ tiêu chí nào bạn có thể có.
Nếu bạn đang tìm kiếm một địa chỉ IP công cộng của hộp , bạn có thể sử dụng như sau:
dig @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \"
Bạn có thể sử dụng dig(1)
các tùy chọn như -4
hoặc -6
đặc biệt tìm kiếm địa chỉ IPv4 hoặc IPv6; Google sẽ cung cấp một câu trả lời trong một bản ghi TXT
loại, trong đó sẽ có các trích dẫn xung quanh nó khi được trình bày bởi dig
; nếu sau đó bạn muốn sử dụng biến với các tiện ích như traceroute
, bạn phải sử dụng cái gì đó như tr (1) để xóa các trích dẫn đã nói.
Các tùy chọn khác bao gồm whoami.akamai.net
và myip.opendns.com
, câu trả lời với A
và AAAA
các bản ghi (thay vì TXT
như trong ví dụ trên từ Google), vì vậy, chúng không yêu cầu xóa các trích dẫn:
dig -4 @ns1-1.akamaitech.net -t a whoami.akamai.net +short
dig -4 @resolver1.opendns.com -t any myip.opendns.com +short
dig -6 @resolver1.opendns.com -t any myip.opendns.com +short
Đây là tập lệnh mẫu sử dụng tất cả các tùy chọn ở trên để đặt các biến:
#!/bin/sh
IPANY="$(dig @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \")"
GOOGv4="$(dig -4 @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \")"
GOOGv6="$(dig -6 @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \")"
AKAMv4="$(dig -4 @ns1-1.akamaitech.net -t a whoami.akamai.net +short)"
CSCOv4="$(dig -4 @resolver1.opendns.com -t a myip.opendns.com +short)"
CSCOv6="$(dig -6 @resolver1.opendns.com -t aaaa myip.opendns.com +short)"
printf '$GOOG:\t%s\t%s\t%s\n' "${IPANY}" "${GOOGv4}" "${GOOGv6}"
printf '$AKAM:\t%s\n$CSCO:\t%s\t%s\n' "${AKAMv4}" "${CSCOv4}" "${CSCOv6}"
Nếu bạn đang tìm kiếm một địa chỉ IP riêng hoặc cho một tập hợp tất cả các địa chỉ IP được gán cho hộp, bạn có thể sử dụng một số kết hợp ifconfig
(trên BSD và GNU / Linux), ip addr
(trên GNU / Linux), hostname
(tùy chọn -i
và -I
bật GNU / Linux) và netstat
để xem những gì đang xảy ra.
hostname -I >> file_name
điều này sẽ làm mọi thứ bạn muốn
hostname: invalid option -- 'l'
...