Как я могу получить свой собственный IP-адрес и сохранить его в переменной в скрипте оболочки?
Как я могу получить свой собственный IP-адрес и сохранить его в переменной в скрипте оболочки?
Ответы:
Это не так просто, если вы хотите принять во внимание WLAN и другие альтернативные интерфейсы. Если вы знаете, для какого интерфейса вам нужен адрес (например, eth0, первая плата Ethernet), вы можете использовать это:
ip="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
Другими словами, получите мне информацию о конфигурации сети, найдите eth0
, получите эту строку и следующую ( -A 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)"
ifconfig eth0
ip address
вместо этого
Я полагаю, что "современные инструменты" способ получить ваш адрес 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)
или что-то типа того.
ip
доступно на всех дистрибутивах Red Hat и Fedora, которые я использовал. ip
является частью пакета iproute2 ( linuxfoundation.org/collaborate/workgroups/networking/iproute2 ). ifconfig
и route
предположительно устарели, хотя они продолжают использоваться многими людьми, особенно в сценариях. ip
по моему мнению, гораздо более приятный.
ip
также доступен на всех дистрибутивах Debian и Debian, которые я видел. Это часть пакета iproute, которая помечена как важная.
ip
является частью пакета iproute2, который по умолчанию является дистрибутивом. Это в большинстве хороших репозиториев. en.wikipedia.org/wiki/Iproute2
/sbin/ip
вместо ip
?
awk
и cut
немного забавно для меня, вот возможная альтернатива, которая на самом деле не может быть лучше:ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
Почему бы просто не сделать IP=$(hostname -I)
?
hostname -i
дает мне просто 127.0.0.1
, hostname -I
дает мне правильный IP-адрес ...
-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-адресом
-I
на FreeBSD, но вы можете использоватьdig +short `hostname -f`
Если вам нужен адрес интерфейса, проще всего установить moreutils, тогда:
anthony@Zia:~$ ifdata -pa br0
172.16.1.244
ifdata
отвечает практически на каждый вопрос, для которого у вас возникнет искушение разобрать ifconfig
вывод.
Если вы хотите узнать свой IP-адрес так, как его видит внешняя сторона (помимо NAT и т. Д.), Существует множество сервисов, которые это сделают. Один из них довольно прост:
anthony@Zia:~$ curl ifconfig.me
173.167.51.137
ifdata
добавить в iproute2
. Возможно, новый бинарный файл называетсяipdata
Чтобы получить адреса 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
исключает временные адреса (если вы хотите, чтобы адрес не менялся)-4
/ -6
фильтровать типы адресов. Вы также можете легко получить другие параметры интерфейса. Лично мне не нравится цикл while, и я предпочитаюgrep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
Зависит от того, что вы подразумеваете под собственным 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 не использует соединение), но подготавливает сокет путем запроса таблицы маршрутизации.
ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')
ipa=$(hostname -i|cut -f2 -d ' ')
-I
вместо -i
лучше, так как вы хотите игнорировать петлевые адреса, поэтому последняя команда будетipa=$(hostname -I|cut -f1 -d ' ')
grep
этого недостаточно, не связывайте это с чем-то другим. Просто используйте что - то другое ( sed
, awk
и т.д.).
Я не хочу быть придурком, но действительно есть верный путь, и это все. Вы обрезаете вывод, 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
поля.
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-адрес.
На FreeBSD вы можете использовать
dig +short `hostname -f`
Это может работать для других сред, в зависимости от вашей настройки.
/etc/resolv.conf
и того, как сетевой маршрутизатор обрабатывает локальные имена хостов. Хорошо использовать это в вашей среде, если вы тестируете это, и оно работает. Но если вы сделаете это, вы создадите «хрупкую» систему, которая вызовет проблемы у других, если вы поделитесь этим. Используйте с осторожностью.
Предполагая, что у вас могут быть различные интерфейсы с разными именами, но вам нужен первый не локальный хост и не ipv6, вы можете попробовать:
ip=`ip addr show |grep "inet " |grep -v 127.0.0. |head -1|cut -d" " -f6|cut -d/ -f1`
Я использую этот однострочник:
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-адрес первого доступного сетевого интерфейса.
Вы должны использовать 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}'
Мне нужно было сделать это в псевдониме, чтобы запустить радиосервер на моем проводном сетевом адаптере. я использовал
ip addr | egrep -i "inet.+eth1" | awk -F[\ /] '{print $6}' | tr -d [:space:]
egrep
амортизируется Используйте grep -E
вместо этого.
Некоторые команды работают с 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 ; } '
Этот фрагмент позволяет избежать жесткого кодирования имени устройства (например, «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'/')
все решения, использующие awk / sed / grep, кажутся слишком сложными и уродливыми для моей ситуации ... поэтому я придумала это действительно простое решение, но остерегайтесь, потому что оно делает некоторые предположения, а именно предположение, что интерфейс LAST - это то, что вы интересно. если вы в порядке с этим, то это довольно чисто:
ifconfig | awk '/net / { x = $2 } END { print x }'
в противном случае вы можете сделать какое-нибудь глупое if
утверждение, чтобы проверить определенный префикс или любые другие критерии, которые у вас могут быть.
Если вы ищете публичный 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
посмотреть, что происходит.
hostname -I >> file_name
это будет делать все, что вы хотите
hostname: invalid option -- 'l'
...