Como obter meu próprio endereço IP e salvá-lo em uma variável em um script de shell?

65

Como posso obter meu próprio endereço IP e salvá-lo em uma variável em um script de shell?

Tom Brito
fonte
2
Uma palavra de cautela: existem muitas respostas "funciona no meu sistema" aqui que podem não ser portáveis ​​para outros ambientes. Você precisa decidir se deseja algo que funcione para você ou algo que possa ser compartilhado. Todo sistema possui vários IPs. Uma solução portátil responde a Q: "que IP eu uso para alcançar blá ?" A solução funciona no meu sistema responde a Q: "qual é o meu IP?" com o A: "Eu acho que você quer dizer este ..." Isso deve ser portáteis unix.stackexchange.com/a/402160/9745
de Bruno Bronosky
Isso fornece uma maneira de obter o endereço IP do formulário / proc: unix.stackexchange.com/questions/365225/…
Pierz

Respostas:

30

Não é tão fácil se você quiser levar em consideração a wlan e outras interfaces alternativas. Se você souber para qual interface deseja o endereço (por exemplo, eth0, a primeira placa Ethernet), poderá usar este:

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

Em outras palavras, obtenha as informações de configuração de rede, procure eth0, obtenha essa linha e a próxima ( -A 1), obtenha apenas a última linha, obtenha a segunda parte dessa linha ao dividir e :, em seguida, obtenha a primeira parte disso ao dividir com espaço.

l0b0
fonte
11
Eu adicionei um adicional grepao seu código para ignorar qualquer interface com "eth0:"; isso agora funciona como eu esperava (fornecendo apenas o endereço IP "eth0" e não quaisquer subinterfaces (eth0: 0, eth0: 1 etc.):ip="$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
6
Você pode pular o primeiro grep usandoifconfig eth0
Bryan Larsen
5
ifconfig está obsoleto, você deve usar em ip addressvez disso
alexises
70

Eu acredito que a maneira "ferramentas modernas" de obter seu endereço ipv4 é analisar 'ip' em vez de 'ifconfig', então seria algo como:

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)

ou algo assim.

jsbillings
fonte
4
ipestá disponível em todas as distribuições Red Hat e Fedora que eu usei. ipfaz parte do pacote iproute2 ( linuxfoundation.org/collaborate/workgroups/networking/iproute2 ). ifconfige routesão supostamente preteridos, embora continuem sendo usados ​​por muitas pessoas, principalmente em scripts. ipé muito mais analisável, na minha opinião.
Jsbillings # 03/03
3
iptambém está disponível em todas as distribuições baseadas em Debian e Debian que eu já vi. Faz parte do pacote iproute que é marcado como importante.
Arrowmaster 3/03
2
É absolutamente assim que deve ser feito. Eu recomendaria as outras respostas para o uso do ifconfig. ipfaz parte do pacote iproute2, que é muitas distribuições por padrão. É na maioria dos bons repositórios de. pt.wikipedia.org/wiki/Iproute2
jwbensley 15/09/12
3
@jsbillings Por que em /sbin/ipvez de ip?
L0b0
11
Esta é uma excelente resposta! A combinação de awke cuté levemente divertida para mim, aqui está uma alternativa possível que pode não ser realmente melhor: #ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
187
32

Por que não simplesmente fazer IP=$(hostname -I)?

Andrei
fonte
3
hostname -idá-me apenas 127.0.0.1, hostname -Idá-me o endereço IP correto ...
student
@student sim, de fato, eu testei-o em uma máquina que pode resolver seu nome de host, como o manpage diz-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
Andrei
Como posso configurar minha máquina para resolver o nome do host?
student
a maneira mais fácil é adicionando-a /etc/hosts, juntamente com o endereço IP correspondente
Andrei
3
Não -Ino FreeBSD, mas você pode usardig +short `hostname -f`
Tigger
24

Se você deseja o endereço de uma interface, a maneira mais fácil é instalar o moreutils:

anthony@Zia:~$ ifdata -pa br0
172.16.1.244

ifdataresponde praticamente todas as perguntas ifconfigpelas quais você seria tentado a analisar a saída.

Se você deseja descobrir o seu endereço IP como o exterior o vê (além de qualquer NAT, etc.), existem muitos serviços que o farão. Um é bastante fácil:

anthony@Zia:~$ curl ifconfig.me
173.167.51.137
derobert
fonte
Oh Deus, obrigado por esta resposta. Nunca ouvi falar de maisutilidades antes. Eu estava pensando seriamente em escrever meu próprio programa C para fazer exatamente isso.
Chris Harrington
Seria bom ter ifdataadicionado iproute2. Talvez um novo binário chamadoipdata
Swiss
ifdata é bom, mas não suporta ipv6.
BringBackCommodore64
15

Para obter endereços IPv4 e IPv6 e não assumir que a interface principal seja eth0(atualmente em1 é mais comum ), tente:

ips=$(ip -o addr show up primary scope global |
      while read -r num dev fam addr rest; do echo ${addr%/*}; done)
  • -outiliza o formato de saída de uma linha, que é mais fácil de processar com read, grep, etc.
  • up exclui dispositivos que não estão ativos
  • scope globalexclui endereços particulares / locais como 127.0.0.1efe80::/64
  • primaryexclui endereços temporários (supondo que você queira um endereço que não seja alterado)
Mikel
fonte
11
Essa deve ser a melhor resposta, pois 1) não assume o nome de um dispositivo, 2) usa 'ip' em oposição ao 'ifconfig' da velha escola e 3) também suporta o ipv6.
BringBackCommodore64
Eu concordei, é o melhor começo para a maioria dos casos de uso. Você pode passar -4/ -6para filtrar os tipos de endereço. Você também pode obter facilmente outros parâmetros de interface. Pessoalmente, eu não gosto while e eu prefirogrep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
Jérôme Pouiller
7

Depende do que você quer dizer com seu próprio endereço IP. Os sistemas têm endereços IP em várias sub-redes (algumas vezes por sub-rede), algumas das quais IPv4, outras IPv6 usando dispositivos como adaptadores Ethernet, interfaces de loopback, túneis VPN, pontes, interfaces virtuais ...

Você quer dizer o endereço IP pelo qual outro dispositivo pode chegar ao seu computador, você precisa descobrir qual sub-rede é essa e qual versão do IP estamos falando. Além disso, lembre-se de que, devido ao NAT executado pelos firewalls / roteadores, o endereço IP de uma interface pode não ser o mesmo que um host remoto vê uma conexão de entrada do seu computador.

Quando há um roteamento de origem sofisticado ou por protocolo / porta, pode ser difícil descobrir qual interface seria usada para conversar com um computador remoto por um determinado protocolo e, mesmo assim, não há garantia de que o endereço IP dessa interface seja diretamente endereçável pelo computador remoto que deseja estabelecer uma nova conexão com o seu computador.

Para o IPv4 (provavelmente também funciona para o IPv6), um truque que funciona em muitos departamentos, incluindo o Linux, para descobrir o endereço IP da interface usada para alcançar um determinado host, é usar um connect (2) em um soquete UDP e usar o nome do obturador ():

Por exemplo, no meu computador doméstico:

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

Seria usado para descobrir o endereço IP da interface através do qual eu alcançaria 8.8.8.8 (servidor DNS do Google). Ele retornaria algo como "192.168.1.123", que é o endereço da interface para a rota padrão para a Internet. No entanto, o Google não vê uma solicitação DNS da minha máquina como proveniente desse endereço IP, que é privado, pois há NAT realizado pelo meu roteador de banda larga doméstico.

connect () em um soquete UDP não envia nenhum pacote (UDP é sem conexão), mas prepara o soquete consultando a tabela de roteamento.

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

ipa=$(hostname -i|cut -f2 -d ' ')
fastrizwaan
fonte
11
Usando -Ivez de -ié melhor que você iria querer ignorar endereços de loopback, então o comando final seriaipa=$(hostname -I|cut -f1 -d ' ')
Karl.S
11
Se grepnão for suficiente, não o coloque em outra coisa. Basta usar a outra coisa ( sed, awk, etc.).
Bruno Bronosky 11/08/1918
7

Não pretendo ser um idiota, mas realmente existe um caminho certo e é isso. Você apara a saída ip routepara obter apenas o IP de origem. Dependendo do IP que você está tentando acessar, "meu próprio endereço IP" (palavras do OP) será diferente. Se você se preocupa em acessar a Internet pública, usar o servidor DNS 8.8.8.8 do Google é bastante padrão. Assim...

A resposta curta é:

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

Aqui está a explicação detalhada

Se eu quero o ip que eu uso para acessar a internet , eu uso o seguinte:

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

Se eu quiser que o ip que eu uso alcance algo na minha VPN , eu uso o seguinte:

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

Este próximo é realmente apenas para fins ilustrativos. Mas, deve funcionar em qualquer sistema Linux. Portanto, você pode usar isso para demonstrar que, sim, todas as máquinas têm vários endereços IP o tempo todo.

Se eu quisesse que o ip que eu utilizasse chegasse a mim , eu usaria o seguinte:

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

Mais sobre esse sedcomando

Primeiro, deixe-me dizer que, ao escolher as ferramentas unix, você tenta escolher as ferramentas que requerem menos tubos. Portanto, embora algumas respostas sejam direcionadas ifconfigde greppara sedpara head, isso raramente é necessário. Quando você o vir, deve ser sinalizado que você está seguindo conselhos de alguém com pouca experiência. Isso não faz a "solução" errada. Mas, provavelmente, poderia usar alguma racionalização.

Eu escolhi sedporque é mais conciso do que o mesmo fluxo de trabalho awk. (Eu tenho desde um exemplo estranho abaixo.) Eu não acho que nenhuma outra ferramenta, mas essas 2 seriam apropriadas.

Vamos examinar o que sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'faz:

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
Nota:

Eu costumava usar, sed -n '/src/{s/.*src *//p;q}'mas um comentarista apontou que alguns sistemas têm dados finais após o srccampo.

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

Mais sobre minha rede

Meus ifconfigprogramas que tenho tun0para minha VPN e eth0para minha 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)
Bruno Bronosky
fonte
ip route get 8.8.8.8 | sed -n '/src/{s/.*src *//p;q}'me deu 10.1.2.3 uid 1002. Então eu adiciono ao anexo | awk '{print $1}'para manter apenas o endereço IP.
wisbucky 23/04
@wisbucky Eu nunca canalizo sed / awk / grep um para o outro no código gravado. (Vou usá-lo na linha de comando quando estiver com pressa, mas você nunca o encontrará gravado em disco que não seja na minha ~ / .bash_history) Atualizei a resposta para usar o awk e resolve esse problema.
Bruno Bronosky
11
@wisbucky Eu não aguentava. Também fiz meu sed trabalhar com seu ambiente.
Bruno Bronosky 24/04
2

No FreeBSD você pode usar

dig +short `hostname -f`

Isso pode funcionar para outros ambientes, depende da sua configuração.

Tigre
fonte
Acredito que isso depende da configuração /etc/resolv.confe de como o roteador de rede lida com nomes de host locais. É bom usar isso em seu ambiente se você testá-lo e funcionar. Mas se você fizer isso, estará criando um sistema "quebradiço" que causará problemas a outros se você compartilhar isso. Use com cuidado.
Bruno Brosky # 1/18
2

Supondo que você possa ter várias interfaces de vários nomes, mas que deseje o primeiro host não local e o não ipv6, tente:

ip=`ip addr show |grep "inet " |grep -v 127.0.0. |head -1|cut -d" " -f6|cut -d/ -f1`
Nicolas
fonte
ip = $ (ifconfig | grep -oP '(? <= inet addr:) \ S *' | grep -v 127)
rcjohnson
1

Eu uso este one-liner:

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

Usa ifconfig(amplamente disponível), não leva localhostendereço, não o vincula a um determinado nome de interface, não leva em consideração o IPv6 e tenta obter o IP da primeira interface de rede disponível.

Andrea Spadaccini
fonte
1
myip=$(curl -kLs "http://api.ipify.org")

ou

myip=$(wget -q "http://api.ipify.org" -O -)
Zibri
fonte
1

Você deve usar ip(em vez de ifconfig) como é atual, mantida e talvez o mais importante para fins de script, produz uma saída consistente e analisável. A seguir, algumas abordagens semelhantes:

Se você deseja o endereço IPv4 para sua interface Ethernet eth0:

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

Como um script:

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

A saída produzida acima está na notação CIDR. Se a notação CIDR não for desejada, ela poderá ser removida:

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

Outra opção que o IMHO é "mais elegante" obtém o endereço IPv4 para qualquer interface usada para conectar-se ao host remoto especificado (8.8.8.8 neste caso). Cortesia de @gatoatigrado em esta resposta :

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

Como um script:

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

Isso funciona perfeitamente bem em um host com uma única interface, mas mais vantajosamente também funcionará em hosts com várias interfaces e / ou especificações de rota.

ipseria minha abordagem preferida, mas certamente não é a única maneira de esfolar esse gato. Aqui está outra abordagem usada hostnamese você preferir algo mais fácil / mais conciso:

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

Ou, se você deseja o endereço IPv6:

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

Eu precisava fazer isso dentro de um alias para iniciar um servidor de rádio na minha NIC com fio. eu usei

ip addr | egrep -i "inet.+eth1" | awk -F[\ /] '{print $6}' | tr -d [:space:]
user208145
fonte
egrepé depreciado. Use em grep -Evez disso.
Yokai
0

Alguns comandos estão trabalhando nos centos 6 ou 7, o comando abaixo trabalhando nos dois,

#!/bin/sh

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

echo $serverip
lakshmikandan
fonte
isso é demais grep | awk | awk. linha pode ser encurtada para/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
Archemar 6/08/15
Eu aceitei, você pode verificar centos6 e 7 ?. centos 7.x / sbin / ifconfig eth0 | awk '$ 1 == "inet" {print substr ($ 2,6); Próximo ; } '35.104.41 centos6.x (funcionando bem) / sbin / ifconfig eth0 | awk '$ 1 == "inet" {print substr ($ 2,6); Próximo ; } '192.168.0.1
lakshmikandan 7/08/2015
0

Supondo que você precise do seu IP público primário , visto do resto do mundo , tente um destes:

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

Este trecho evita codificar o nome do dispositivo (como 'eth0') e usará em ipvez de ifconfig:

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

Ele retornará o IP do primeiro dispositivo ativo listado na saída de ip addr. Dependendo da sua máquina, este pode ser um endereço ipv4 ou ipv6.

Para armazená-lo em uma variável, use:

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

todas as soluções que usam awk / sed / grep parecem muito complexas e feias para a minha situação ... então, eu vim com essa solução realmente simples, mas cuidado, pois ela faz algumas suposições, a saber, a suposição de que a ÚLTIMA interface é a que você está interessado. se você estiver bem com isso, isso é bastante limpo:

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

caso contrário, você poderá fazer uma ifdeclaração boba para testar um prefixo específico ou qualquer critério que possa ter.

mad.meesh
fonte
0

Comando simples para refinar o endereço IP com interface padrão.

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

Testado em todos os sistemas operacionais Unix

MSArun
fonte
0

Essa pode não ser a solução mais robusta ou correta, mas, diferentemente da maioria das outras soluções, o comando funciona no Linux e no Mac (BSD).

host `hostname` | awk '{print $NF}'
wisbucky
fonte
0

Se você estiver procurando por um endereço IP público da caixa , use o seguinte:

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

Você pode usar dig(1)opções como -4ou -6procurar especificamente um endereço IPv4 ou IPv6; O Google fornecerá uma resposta em um registro do TXTtipo, que terá aspas quando apresentado por dig; se você quiser usar a variável posteriormente com utilitários como traceroute, precisará usar algo como tr (1) para remover as citações.

Outras opções incluem whoami.akamai.nete myip.opendns.com, que respondem com Ae AAAAregistros (em vez de TXTno exemplo acima do Google), portanto, não exigem a remoção das aspas:

  • 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

Aqui está um exemplo de script que usa todas as opções acima para definir as variáveis:

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

Se você estiver procurando por um endereço IP privado ou por um conjunto de todos os endereços IP atribuídos à caixa, poderá usar uma combinação de ifconfig(no BSD e GNU / Linux), ip addr(no GNU / Linux), hostname(opções -ie -Iem GNU / Linux) e netstatpara ver o que está acontecendo.

cnst
fonte
-2
hostname -I >> file_name 

isso fará tudo o que você quiser

Shanu
fonte
hostname: invalid option -- 'l'...
jasonwryan
Isso é um capital i. Parece funcionar bem, embora aparentemente imprima endereços IP de todas as interfaces.
Joe
é proposto em uma das respostas anteriores. Também não armazena o IP na variável. Então, qual é o objetivo dessa resposta?
Jakuje