Як отримати власну IP-адресу та зберегти її до змінної у сценарії оболонки?


65

Як я можу отримати власну IP-адресу та зберегти її до змінної у сценарії оболонки?


2
Слова застереження: Тут є багато відповідей на "роботу над моєю системою", які можуть не переноситися для інших середовищ. Ви повинні вирішити, чи хочете ви щось, що працює для вас, або щось, чим можна поділитися. Кожна система має кілька IP-адрес. Портативне рішення відповідає Q: «що IP я використовувати , щоб досягти бла ?» Робота над моїм системним рішенням відповідає на запитання: "що таке мій IP?" з A: "Я думаю, ви маєте на увазі це ..." Це повинно бути портативним unix.stackexchange.com/a/402160/9745
Бруно Броноський

Це забезпечує спосіб отримання форми IP - адреса / Proc: unix.stackexchange.com/questions/365225 / ...
Пірз

Відповіді:


30

Це не так просто, якщо ви хочете врахувати wlan та інші альтернативні інтерфейси. Якщо ви знаєте, для якого інтерфейсу ви хочете адресу (наприклад, eth0, перша Ethernet-карта), ви можете скористатися цим:

ip="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"

Іншими словами, отримайте мені інформацію про конфігурацію мережі, шукайте eth0, отримайте цей рядок та наступний ( -A 1), отримайте лише останній рядок, отримайте другу частину цього рядка при розбитті з :, а потім отримайте першу частину цього при розбитті з простором.


1
Я додав ваш додатковий grepкод, щоб ігнорувати будь-який інтерфейс з "eth0:" в ньому; це зараз працює, як я очікував (даючи лише IP-адресу "eth0", а не будь-які ip="$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"

6
Ви можете пропустити перший греп, скориставшисьifconfig eth0
Брайан Ларсен

5
якщоконфігурація застаріла, слід скористатися ip addressнатомість
скасовує

70

Я вважаю, що "сучасними інструментами" спосіб отримати вашу ipv4 адресу - це проаналізувати "ip", а не "ifconfig", тож це буде щось на кшталт:

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)

чи щось подібне.


4
ipдоступний у всіх дистрибутивах Red Hat та Fedora, якими я користувався. ipє частиною пакету iproute2 ( linuxfoundation.org/collaborate/workgroups/networking/iproute2 ). ifconfigі routeвони нібито застаріли, хоча їх продовжує використовувати багато людей, особливо в сценаріях. ipНа мій погляд, він набагато проаналізованіший.
jsbillings

3
ipтакож доступний у всіх дистрибутивах на базі Debian та Debian. Це частина пакету iproute, яка позначена як важлива.
Arrowmaster

2
Це абсолютно так, як це слід зробити, я б спростував інші відповіді на їх використання ifconfig. ipє частиною пакету iproute2, який за замовчуванням має багато дистрибутивів. Це в більшості хороших репостів. en.wikipedia.org/wiki/Iproute2
jwbensley

3
@jsbillings Чому /sbin/ipзамість ip?
l0b0

1
Це відмінна відповідь! Поєднання awkі cutце злегка забавно для мене, ось можлива альтернатива , яка не може бути на самом деле краще:ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
Швейцарське

32

Чому б просто не зробити IP=$(hostname -I)?


3
hostname -iдає мені просто 127.0.0.1, hostname -Iдає мені правильну IP-адресу ...
студент

@student так, я справді перевірив це на машині, яка може вирішити своє ім'я хоста, як пише manpage-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разом із відповідною IP-адресою
Андрій

3
Ні -Iна FreeBSD, але ви можете використовуватиdig +short `hostname -f`
Tigger

24

Якщо ви хочете адресу інтерфейсу, найпростішим способом є встановлення додаткових утиліт:

anthony@Zia:~$ ifdata -pa br0
172.16.1.244

ifdataвідповідає майже на кожне запитання, на яке ви б спокусилися проаналізувати ifconfigвихід.

Якщо ви хочете дізнатися вашу IP-адресу, коли її бачать зовні (поза будь-яким NAT і т.д.), існує безліч служб, які будуть це робити. Один досить простий:

anthony@Zia:~$ curl ifconfig.me
173.167.51.137

О боже, дякую за цю відповідь. Ніколи раніше не чув про корисніше. Я серйозно розглядав можливість написання власної маленької програми на C, щоб зробити саме це.
Кріс Харрінгтон

Було б непогано ifdataдодати iproute2. Можливо, новий бінарний під назвоюipdata
швейцарський

ifdata хороший, Але він не підтримує ipv6.
BringBackCommodore64

15

Щоб отримати адреси IPv4 та IPv6, а не припустити, що основний інтерфейс є eth0(ці дні em1 зустрічаються частіше ), спробуйте:

ips=$(ip -o addr show up primary scope global |
      while read -r num dev fam addr rest; do echo ${addr%/*}; done)
  • -oвикористовує формат виведення одного рядка, який легше обробляти з read, grepі так далі
  • up виключає неактивні пристрої
  • scope globalвиключає приватні / локальні адреси, такі як 127.0.0.1таfe80::/64
  • primaryвиключає тимчасові адреси (припустимо, що ви хочете адресу, яка не змінюється)

1
Це має бути найкращою відповіддю, оскільки 1) він не передбачає ім'я пристрою; 2) він використовує "ip" на відміну від старої школи "ifconfig", і 3) він також підтримує ipv6.
BringBackCommodore64

Я погодився, це найкращий початок для більшості випадків використання. Ви можете передавати -4/ -6фільтрувати типи адрес. Ви також можете легко отримати інші параметри інтерфейсу. Особисто мені не подобається цикл, і я вважаю за кращеgrep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
Jérôme Pouiller

7

Залежить від того, що ви маєте на увазі під власною IP-адресою. Системи мають IP-адреси в декількох підмережах (іноді по кілька в підмережі), деякі з яких IPv4, деякі IPv6 з використанням таких пристроїв, як адаптери Ethernet, інтерфейси зворотного зв'язку, тунелі VPN, мости, віртуальні інтерфейси ...

Я маю на увазі IP-адресу, за якою інший пристрій може дістатися до вашого комп’ютера, ви повинні з’ясувати, яка саме підмережа є і про яку версію IP ми говоримо. Також майте на увазі, що через NAT, що виконується брандмауером / маршрутизаторами, IP-адреса інтерфейсу може бути не такою, як віддалений хост бачить вхідне з'єднання з вашого комп'ютера.

Якщо є фантазійне джерело маршрутизації або по протоколу / порту маршрутизації, може бути важко дізнатися, який інтерфейс буде використовуватися для спілкування з одним віддаленим комп'ютером по даному протоколу, і навіть тоді, немає гарантії, що IP-адреса цього інтерфейсу може бути безпосередньо адресується віддаленим комп'ютером, який хоче встановити нове з'єднання з вашим комп'ютером.

Для IPv4 (ймовірно, працює і для IPv6), трюк, який працює в багатьох уніках, включаючи Linux, щоб дізнатися IP-адресу інтерфейсу, який використовується для досягнення даного хоста, - використовувати підключення (2) в UDP-сокет і використовувати getsockname ():

Наприклад, на моєму домашньому комп’ютері:

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]);'

Була б використана для з'ясування IP-адреси інтерфейсу, через який я б досяг 8.8.8.8 (DNS-сервер google). Він поверне щось подібне до "192.168.1.123", що є адресою інтерфейсу для маршруту за замовчуванням до Інтернету. Однак google не побачив би запит DNS від моєї машини, як той, що надходить з тієї IP-адреси, яка є приватною, оскільки існує NAT, виконаний моїм домашнім широкосмуговим маршрутизатором.

connect () у UDP-розетці не надсилає жодного пакету (UDP відсутній підключення), але готує сокет за допомогою запиту таблиці маршрутизації.


7
ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')

ipa=$(hostname -i|cut -f2 -d ' ')

1
Використовувати -Iзамість цього -iкраще, як ви хотіли б ігнорувати адреси зворотного зв'язку, тому остаточною командою будеipa=$(hostname -I|cut -f1 -d ' ')
Karl.S

1
Якщо grepцього недостатньо, не перекладайте його на щось інше. Просто використовуйте що - то інше ( sed, awkі т.д.).
Бруно Броноський,

7

Я не хочу бути ривком, але насправді є вірний шлях, і це все. Ви обрізаєте вихід, ip routeщоб отримати тільки вихідний IP. Залежно від того, до якого IP ви намагаєтесь дістатися, "моя власна IP-адреса" (слова ОП) буде різною. Якщо ви хочете отримати доступ до загальнодоступного Інтернету, використання сервера DNS 8.8.8.8 Google є досить стандартним. Тому...

Коротка відповідь:

ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'

Ось детальне пояснення

Якщо я хочу, щоб ip, який я використовую, дійшов до Інтернету , я користуюся цим:

pi@et3:~ $ ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
10.55.0.200

Якщо я хочу, щоб я використовував ip, щоб досягти чогось у своєму VPN , я використовую це:

pi@et3:~ $ ip route get 172.31.0.100 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
172.29.0.9

Цей наступний дійсно лише для ілюстративних цілей. Але це має працювати в будь-якій системі Linux. Отже, ви можете використовувати це, щоб продемонструвати, що так, всі машини мають декілька IP-адрес у будь-який час.

Якби я хотів, щоб ip, який я використовую, досягнув себе , я би використав це:

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команду

Спершу дозвольте сказати, що, вибираючи інструменти unix, ви намагаєтеся вибрати інструменти, для яких потрібні найменші труби. Таким чином, в той час як деякі відповіді будуть труби ifconfigдо grepдо sedдо head, що рідко коли це необхідно. Коли ви це побачите, він повинен підняти червоний прапор, що ви приймаєте поради від когось із мало досвіду. Це не робить "рішення" неправильним. Але, мабуть, це могло б використати деяку оптимізацію.

Я вибрав, sedтому що він більш короткий, ніж той самий робочий процес у awk. (Я маю з дивовижного прикладу нижче.) Я не думаю, що будь-який інший інструмент, крім цих 2, був би відповідним.

Розберемо, що 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
Примітка:

Раніше я використовував, sed -n '/src/{s/.*src *//p;q}'але коментатор зазначив, що деякі системи мають слідові дані після srcполя.

Використання awk

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

Більше про мою мережу

Мої ifconfigшоу, що я маю tun0для свого VPN та eth0для мого LAN.

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}'дав мені 10.1.2.3 uid 1002. Тож додаю додати, | awk '{print $1}'щоб зберегти лише IP-адресу.
Вісбукі

@wisbucky Я ніколи не передаю sed / awk / grep один одному у записаний код. (Я буду використовувати його в командному рядку, коли я поспішаю, але ви ніколи не знайдете його записаним на інший диск, ніж у моїй ~ / .bash_history) Я оновив відповідь на використання awk, і це вирішує це питання.
Бруно Броноський

1
@wisbucky Я не витримав. Я також змусив свою седу працювати з вашим оточенням.
Бруно Броноський,

2

На FreeBSD ви можете користуватися

dig +short `hostname -f`

Це може працювати в інших середовищах, залежно від налаштування.


Я вважаю, що це залежить від конфігурації /etc/resolv.confта того, як мережевий маршрутизатор обробляє локальні імена хостів. Це добре використовувати це у вашому оточенні, якщо ви протестуєте його, і воно працює. Але якщо ви так зробите, ви будуєте "крихку" систему, яка буде створювати інші проблеми, якщо ви поділитесь цим. Використовуйте обережно.
Бруно Броноський

2

Якщо припустити, що у вас можуть бути різні інтерфейси різного імені, але що вам потрібен перший не локальний хост і non-ipv6, ви можете спробувати:

ip=`ip addr show |grep "inet " |grep -v 127.0.0. |head -1|cut -d" " -f6|cut -d/ -f1`

ip = $ (ifconfig | grep -oP '(? <= inet addr:) \ S *' | grep -v 127)
rcjohnson

1

Я використовую цей одношаровий:

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-)

Використовує ifconfig(широко доступний), не приймає localhostадреси, не прив'язує вас до заданого імені інтерфейсу, не враховує IPv6 та намагається отримати IP першого мережевого інтерфейсу доступним.



1

Ви повинні використовувати ip(замість ifconfig), оскільки він є поточним, підтримуваним і, можливо, найголовніше для сценаріїв, він дає послідовний та прохідний вихід. Нижче наведено кілька подібних підходів:

Якщо ви хочете адресу IPv4 для вашого інтерфейсу Ethernet eth0:

$ ip -4 -o addr show eth0 | awk '{print $4}'
192.168.1.166/24  

Як сценарій:

$ INTFC=eth0  
$ MYIPV4=$(ip -4 -o addr show $INTFC | awk '{print $4}') 
$ echo $MYIPV4
192.168.1.166/24

Вихід, отриманий вище, знаходиться у позначенні CIDR. Якщо позначення CIDR не потрібне, його можна зняти:

$ ip -4 -o addr show eth0 | awk '{print $4}' | cut -d "/" -f 1 
192.168.1.166  

Інший варіант, що IMHO є "найелегантнішим", отримує IPv4-адресу для будь-якого інтерфейсу, який використовується для підключення до вказаного віддаленого хоста (8.8.8.8 в цьому випадку). Людськість @gatoatigrado у цій відповіді :

$ ip route get 8.8.8.8 | awk '{ print $NF; exit }'
192.168.1.166

Як сценарій:

$ RHOST=8.8.8.8  
$ MYIP=$(ip route get $RHOST | awk '{ print $NF; exit }')
$ echo $MYIP
192.168.1.166

Це прекрасно працює на хості з єдиним інтерфейсом, але більш вигідно буде працювати і на хостах з декількома інтерфейсами та / або специфікаціями маршруту.

ipбув би моїм переважним підходом, але це, звичайно, не єдиний спосіб зібрати цю кішку. Ось ще один підхід, який використовується, hostnameякщо ви віддаєте перевагу щось легше / стисліше:

$ hostname --all-ip-addresses | awk '{print $1}'  

Або якщо ви хочете адресу IPv6:

$ hostname --all-ip-addresses | awk '{print $2}'  

0

Мені потрібно було це зробити в псевдонімі, щоб запустити радіосервер на моєму проводному NIC. я використав

ip addr | egrep -i "inet.+eth1" | awk -F[\ /] '{print $6}' | tr -d [:space:]

egrepамортизується. Використовуйте grep -Eзамість цього.
Йокай

0

Деякі команди працюють на centos 6 або 7, нижче команда працює над обома,

#!/bin/sh

serverip=`/sbin/ifconfig eth0 | grep "inet" | awk '{print $2}' | awk 'NR==1' | cut -d':' -f2`

echo $serverip

це занадто багато grep | awk | awk. лінію можна скоротити до/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
Архемар

Я прийняв, чи можете ви перевірити як centos6, так і 7 ?. centos 7.x / sbin / ifconfig eth0 | awk '$ 1 == "inet" {print substr ($ 2,6); наступний; } '35.104.41 centos6.x (добре працює) / sbin / ifconfig eth0 | awk '$ 1 == "inet" {print substr ($ 2,6); наступний; } '192.168.0.1
лакшмікандан

0

Припустимо, що вам потрібен ваш основний публічний IP-код, як це видно з усього світу , спробуйте будь-який із них:

wget http://ipecho.net/plain -O - -q
curl http://icanhazip.com
curl http://ifconfig.me/ip

0

Цей фрагмент дозволяє уникнути жорсткого кодування назви пристрою (наприклад, 'eth0') і використовуватиме ipзамість ifconfig:

/sbin/ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1  -d'/'

Він поверне IP першого активного пристрою, зазначеного у висновку ip addr. Залежно від вашої машини, це може бути ipv4 або ipv6.

Щоб зберегти його у змінній, використовуйте:

ip=$(/sbin/ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1  -d'/')

0

всі рішення, що використовують awk / sed / grep, здаються занадто складними та некрасивими для моєї ситуації ... тому я придумав це дійсно просте рішення, Але будьте обережні, тому що він робить деякі припущення, а саме припущення, що ОСТАННІЙ інтерфейс - це ви зацікавлений. якщо ви з цим все гаразд, то це досить чисто:

ifconfig | awk '/net / { x = $2 } END { print x }'

інакше ви можете зробити якесь дурне ifтвердження, щоб перевірити певний префікс або будь-які критерії.


0

Проста команда для тонкої IP-адреси з інтерфейсом за замовчуванням.

ip route | grep src | awk '{print $NF; exit}'

Тестовано на всіх ОС Unix


0

Це може бути не найнадійнішим чи правильним рішенням, але на відміну від більшості інших рішень, команда працює як на Linux, так і на Mac (BSD).

host `hostname` | awk '{print $NF}'

0

Якщо ви шукаєте загальнодоступну IP-адресу цього поля , ви можете скористатися наступним:

  • dig @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \"

Ви можете використовувати dig(1)такі параметри, як -4або -6спеціально шукати адресу IPv4 або IPv6; Google надасть відповідь у записі TXTтипу, який буде мати цитати, коли вони будуть представлені dig; якщо ви хочете згодом використовувати змінну з утилітами типу traceroute, ви повинні використовувати щось на зразок tr (1) для видалення зазначених лапок.

Інші параметри включають whoami.akamai.netі myip.opendns.com, які відповідають Aі AAAAзаписують (замість того, TXTяк у наведеному вище прикладі від Google), тому вони не вимагають видалення лапок:

  • 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

Ось зразок сценарію, який використовує всі параметри вище для встановлення змінних:

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

Якщо ви шукаєте приватну IP-адресу або набір усіх IP-адрес, призначених у вікні, ви можете використовувати комбінацію ifconfig(у BSD та GNU / Linux), ip addr(у GNU / Linux), hostname(параметри -iта -Iна GNU / Linux) і netstatподивитися, що відбувається.


-2
hostname -I >> file_name 

це зробить все, що ви хочете


hostname: invalid option -- 'l'...
Jasonwryan

Це капітал i. Здається, добре працює, хоча, мабуть, друкує IP-адреси всіх інтерфейсів.
Джо

це пропонується в одній з попередніх відповідей. Крім того, він не зберігає IP в змінній. Тож у чому сенс цієї відповіді?
Jakuje
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.