Как получить свой собственный IP-адрес и сохранить его в переменной в скрипте оболочки?

65

Как я могу получить свой собственный IP-адрес и сохранить его в переменной в скрипте оболочки?

Том Брито
источник
2
Предостережение: здесь есть много ответов «работает в моей системе», которые могут быть не переносимы в другие среды. Вы должны решить, хотите ли вы что-то, что работает для вас, или что-то, чем можно поделиться. Каждая система имеет несколько IP-адресов. Портативное решение отвечает Q: «что IP я использовать , чтобы достичь бла ?» A работает над решением моей системы отвечает на вопрос: "Какой у меня IP?" с буквой
Бруно Броноски
Это обеспечивает способ получения формы 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), получите только последнюю строку, получите вторую часть этой строки при разделении с :, затем получите первую часть этого при разделении с пространством.

l0b0
источник
1
Я добавил дополнительный grepкод в ваш код, чтобы игнорировать любой интерфейс с "eth0:" в нем; теперь это работает, как я ожидаю (давая только IP-адрес "eth0", а не какие-либо подчиненные интерфейсы (eth0: 0, eth0: 1 и т. д.):ip="$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
6
Вы можете пропустить первый grep, используяifconfig eth0
Bryan Larsen
5
ifconfig устарела, вы должны использовать ip addressвместо этого
alexises
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)

или что-то типа того.

jsbillings
источник
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?
10
1
Это отличный ответ! Сочетание awkи cutнемного забавно для меня, вот возможная альтернатива, которая на самом деле не может быть лучше:ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
Swiss
32

Почему бы просто не сделать IP=$(hostname -I)?

Андрей
источник
3
hostname -iдает мне просто 127.0.0.1, hostname -Iдает мне правильный IP-адрес ...
студент
@student да, действительно, я проверил его на машине, которая может разрешить его имя хоста, как говорится на странице руководства-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-адресом
Andrei
3
Нет -Iна FreeBSD, но вы можете использоватьdig +short `hostname -f`
Tigger
24

Если вам нужен адрес интерфейса, проще всего установить moreutils, тогда:

anthony@Zia:~$ ifdata -pa br0
172.16.1.244

ifdataотвечает практически на каждый вопрос, для которого у вас возникнет искушение разобрать ifconfigвывод.

Если вы хотите узнать свой IP-адрес так, как его видит внешняя сторона (помимо NAT и т. Д.), Существует множество сервисов, которые это сделают. Один из них довольно прост:

anthony@Zia:~$ curl ifconfig.me
173.167.51.137
derobert
источник
О боже, спасибо за этот ответ. Никогда не слышал о moreutils раньше. Я серьезно подумывал написать свою собственную маленькую C-программу, чтобы сделать именно это.
Крис Харрингтон
Было бы неплохо ifdataдобавить в iproute2. Возможно, новый бинарный файл называетсяipdata
Swiss
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исключает временные адреса (если вы хотите, чтобы адрес не менялся)
Mikel
источник
1
Это должен быть лучший ответ, потому что 1) он не принимает имя устройства, 2) использует ip в отличие от старой школы ifconfig и 3) также поддерживает ipv6.
BringBackCommodore64
Я согласился, это лучшее начало для большинства случаев использования. Вы можете передавать -4/ -6фильтровать типы адресов. Вы также можете легко получить другие параметры интерфейса. Лично мне не нравится цикл while, и я предпочитаюgrep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
Жером Пуйлер
7

Зависит от того, что вы подразумеваете под собственным IP-адресом. Системы имеют IP-адреса в нескольких подсетях (иногда несколько в каждой подсети), некоторые из которых IPv4, некоторые IPv6 используют такие устройства, как сетевые адаптеры, петлевые интерфейсы, VPN-туннели, мосты, виртуальные интерфейсы ...

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

При наличии причудливой маршрутизации от источника или по протоколу / порту может быть сложно определить, какой интерфейс будет использоваться для связи с одним удаленным компьютером по заданному протоколу, и даже в этом случае нет гарантии, что IP-адрес этого интерфейса может быть напрямую адресуется удаленным компьютером, желающим установить новое соединение с вашим компьютером.

Для IPv4 (вероятно, работает и для IPv6), хитрость, которая работает во многих приложениях, включая Linux, для определения IP-адреса интерфейса, используемого для доступа к данному хосту, заключается в использовании connect (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 ' ')
fastrizwaan
источник
1
Использование -Iвместо -iлучше, так как вы хотите игнорировать петлевые адреса, поэтому последняя команда будетipa=$(hostname -I|cut -f1 -d ' ')
Karl.S
1
Если grepэтого недостаточно, не связывайте это с чем-то другим. Просто используйте что - то другое ( sed, awkи т.д.).
Бруно Броноски
7

Я не хочу быть придурком, но действительно есть верный путь, и это все. Вы обрезаете вывод, ip routeчтобы получить только исходный IP. В зависимости от того, какой IP вы пытаетесь достичь, «мой собственный IP-адрес» (слова ОП) будет отличаться. Если вы хотите получить доступ к общедоступному Интернету, использование DNS-сервера Google 8.8.8.8 довольно стандартно. Так...

Краткий ответ:

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. (У меня есть пример 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для моей локальной сети.

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`

Это может работать для других сред, в зависимости от вашей настройки.

Tigger
источник
Я считаю, что это зависит от конфигурации /etc/resolv.confи того, как сетевой маршрутизатор обрабатывает локальные имена хостов. Хорошо использовать это в вашей среде, если вы тестируете это, и оно работает. Но если вы сделаете это, вы создадите «хрупкую» систему, которая вызовет проблемы у других, если вы поделитесь этим. Используйте с осторожностью.
Бруно Броноски
2

Предполагая, что у вас могут быть различные интерфейсы с разными именами, но вам нужен первый не локальный хост и не 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
myip=$(curl -kLs "http://api.ipify.org")

или же

myip=$(wget -q "http://api.ipify.org" -O -)
Zibri
источник
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

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

ip addr | egrep -i "inet.+eth1" | awk -F[\ /] '{print $6}' | tr -d [:space:]
user208145
источник
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
lakshmikandan
источник
это слишком много grep | awk | awk. линия может быть сокращена до/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
Archemar
Я согласился, вы можете проверить оба 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
lakshmikandan
0

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

wget http://ipecho.net/plain -O - -q
curl http://icanhazip.com
curl http://ifconfig.me/ip
Putnik
источник
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, кажутся слишком сложными и уродливыми для моей ситуации ... поэтому я придумала это действительно простое решение, но остерегайтесь, потому что оно делает некоторые предположения, а именно предположение, что интерфейс LAST - это то, что вы интересно. если вы в порядке с этим, то это довольно чисто:

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

в противном случае вы можете сделать какое-нибудь глупое ifутверждение, чтобы проверить определенный префикс или любые другие критерии, которые у вас могут быть.

mad.meesh
источник
0

Простая команда для точного IP-адреса с интерфейсом по умолчанию.

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

Протестировано на всех ОС Unix

MSArun
источник
0

Возможно, это не самое надежное или правильное решение, но в отличие от большинства других решений, команда работает как на Linux, так и на Mac (BSD).

host `hostname` | awk '{print $NF}'
wisbucky
источник
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посмотреть, что происходит.

CNST
источник
-2
hostname -I >> file_name 

это будет делать все, что вы хотите

Shanu
источник
hostname: invalid option -- 'l'...
Джейсонвриан
Это столица я. Кажется, работает нормально, хотя, по-видимому, печатает IP-адреса всех интерфейсов.
Джо
это предлагается в одном из предыдущих ответов. Также он не хранит IP в переменной. Так в чем смысл этого ответа?
Jakuje