Как я могу получить свой собственный 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::/64primaryисключает временные адреса (если вы хотите, чтобы адрес не менялся)-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'...