Como posso obter meu próprio endereço IP e salvá-lo em uma variável em um script de shell?
Como posso obter meu próprio endereço IP e salvá-lo em uma variável em um script de shell?
Respostas:
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.
grep
ao 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)"
ifconfig eth0
ip address
vez disso
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.
ip
está disponível em todas as distribuições Red Hat e Fedora que eu usei. ip
faz parte do pacote iproute2 ( linuxfoundation.org/collaborate/workgroups/networking/iproute2 ). ifconfig
e route
são supostamente preteridos, embora continuem sendo usados por muitas pessoas, principalmente em scripts. ip
é muito mais analisável, na minha opinião.
ip
també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.
ip
faz parte do pacote iproute2, que é muitas distribuições por padrão. É na maioria dos bons repositórios de. pt.wikipedia.org/wiki/Iproute2
/sbin/ip
vez de ip
?
awk
e 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] }'
Por que não simplesmente fazer IP=$(hostname -I)
?
hostname -i
dá-me apenas 127.0.0.1
, hostname -I
dá-me o endereço IP correto ...
-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
, juntamente com o endereço IP correspondente
-I
no FreeBSD, mas você pode usardig +short `hostname -f`
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
ifdata
responde praticamente todas as perguntas ifconfig
pelas 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
ifdata
adicionado iproute2
. Talvez um novo binário chamadoipdata
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)
-o
utiliza 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 ativosscope global
exclui endereços particulares / locais como 127.0.0.1
efe80::/64
primary
exclui endereços temporários (supondo que você queira um endereço que não seja alterado)-4
/ -6
para 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 ' '
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.
ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')
ipa=$(hostname -i|cut -f2 -d ' ')
-I
vez de -i
é melhor que você iria querer ignorar endereços de loopback, então o comando final seriaipa=$(hostname -I|cut -f1 -d ' ')
grep
não for suficiente, não o coloque em outra coisa. Basta usar a outra coisa ( sed
, awk
, etc.).
Não pretendo ser um idiota, mas realmente existe um caminho certo e é isso. Você apara a saída ip route
para 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...
ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
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
sed
comandoPrimeiro, deixe-me dizer que, ao escolher as ferramentas unix, você tenta escolher as ferramentas que requerem menos tubos. Portanto, embora algumas respostas sejam direcionadas ifconfig
de grep
para sed
para 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 sed
porque é 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 src
campo.
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}}}'
Meus ifconfig
programas que tenho tun0
para minha VPN e eth0
para 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)
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.
No FreeBSD você pode usar
dig +short `hostname -f`
Isso pode funcionar para outros ambientes, depende da sua configuração.
/etc/resolv.conf
e 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.
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`
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 localhost
endereç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.
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.
ip
seria minha abordagem preferida, mas certamente não é a única maneira de esfolar esse gato. Aqui está outra abordagem usada hostname
se 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}'
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:]
egrep
é depreciado. Use em grep -E
vez disso.
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
grep | awk | awk
. linha pode ser encurtada para/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
Este trecho evita codificar o nome do dispositivo (como 'eth0') e usará em ip
vez 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'/')
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 if
declaração boba para testar um prefixo específico ou qualquer critério que possa ter.
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 -4
ou -6
procurar especificamente um endereço IPv4 ou IPv6; O Google fornecerá uma resposta em um registro do TXT
tipo, 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.net
e myip.opendns.com
, que respondem com A
e AAAA
registros (em vez de TXT
no 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 -i
e -I
em GNU / Linux) e netstat
para ver o que está acontecendo.
hostname -I >> file_name
isso fará tudo o que você quiser
hostname: invalid option -- 'l'
...