Jak mogę uzyskać własny adres IP i zapisać go w zmiennej w skrypcie powłoki?
Jak mogę uzyskać własny adres IP i zapisać go w zmiennej w skrypcie powłoki?
Odpowiedzi:
To nie jest takie proste, jeśli chcesz wziąć pod uwagę sieć WLAN i inne alternatywne interfejsy. Jeśli wiesz, dla którego interfejsu chcesz mieć adres (np. Eth0, pierwsza karta Ethernet), możesz użyć tego:
ip="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
Innymi słowy, uzyskaj mi informacje o konfiguracji sieci, poszukaj eth0
, pobierz tę linię i następną ( -A 1
), pobierz tylko ostatnią linię, pobierz drugą część tej linii przy dzieleniu :
, a następnie uzyskaj pierwszą część przy dzieleniu z przestrzenią.
grep
kod do zignorowania dowolnego interfejsu z „eth0:” w nim; działa to teraz tak, jak się spodziewam (podając tylko adres IP „eth0”, a nie żadnych pod-interfejsów (eth0: 0, eth0: 1 itd.):ip="$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
ifconfig eth0
ip address
zamiast tego
Uważam, że „nowoczesnymi narzędziami” do uzyskania adresu IPv4 jest parsowanie „ip” zamiast „ifconfig”, więc byłoby to coś w stylu:
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)
czy coś takiego.
ip
jest dostępny we wszystkich dystrybucjach Red Hat i Fedora, z których korzystałem. ip
jest częścią pakietu iproute2 ( linuxfoundation.org/collaborate/workgroups/networking/iproute2 ). ifconfig
i route
podobno są przestarzałe, chociaż nadal są używane przez wiele osób, szczególnie w skryptach. ip
jest o wiele bardziej możliwe do przeanalizowania, w moim stanie.
ip
jest również dostępny we wszystkich dystrybucjach Debiana i Debiana, które widziałem. Jest to część pakietu iproute, która jest oznaczona jako ważna.
ip
jest częścią pakietu iproute2, który domyślnie ma wiele dystrybucji. Jest w większości dobrych repo. en.wikipedia.org/wiki/Iproute2
/sbin/ip
zamiast ip
?
awk
i cut
jest dla mnie raczej zabawne, oto możliwa alternatywa, która może nie być lepsza:ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
Dlaczego po prostu nie zrobić IP=$(hostname -I)
?
hostname -i
daje mi tylko 127.0.0.1
, hostname -I
podaje prawidłowy adres 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
wraz z odpowiednim adresem IP
-I
na FreeBSD, ale możesz użyćdig +short `hostname -f`
Jeśli potrzebujesz adresu interfejsu, najprostszym sposobem jest zainstalowanie moreutils, a następnie:
anthony@Zia:~$ ifdata -pa br0
172.16.1.244
ifdata
odpowiada prawie na każde pytanie, na które miałbyś ochotę przeanalizować ifconfig
wyniki.
Jeśli chcesz znaleźć swój adres IP tak, jak widzi go z zewnątrz (poza NAT, itp.), Istnieje wiele usług, które to zrobią. Jedno jest dość łatwe:
anthony@Zia:~$ curl ifconfig.me
173.167.51.137
ifdata
dodać iproute2
. Może nowy plik binarny o nazwieipdata
Aby uzyskać adresy IPv4 i IPv6 i nie zakładać, że główny interfejs to eth0
(te dni em1
są bardziej powszechne ), spróbuj:
ips=$(ip -o addr show up primary scope global |
while read -r num dev fam addr rest; do echo ${addr%/*}; done)
-o
wykorzystuje format wyjściowy jednego wiersza, który jest łatwiejszy do przetworzenia z read
, grep
itpup
wyklucza urządzenia, które nie są aktywnescope global
nie obejmuje adresów prywatnych / lokalnych, takich jak 127.0.0.1
ife80::/64
primary
wyklucza adresy tymczasowe (zakładając, że potrzebujesz adresu, który się nie zmienia)-4
/, -6
aby przefiltrować typy adresów. Możesz także łatwo uzyskać inne parametry interfejsu. Osobiście nie lubię podczas pętli i wolęgrep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
Zależy, co rozumiesz przez własny adres IP. Systemy mają adresy IP w kilku podsieciach (czasami kilka w podsieci), niektóre z nich IPv4, niektóre IPv6 używają urządzeń takich jak adaptery Ethernet, interfejsy sprzężenia zwrotnego, tunele VPN, mosty, interfejsy wirtualne ...
Mam na myśli adres IP, pod którym inne dane urządzenie może dotrzeć do twojego komputera, musisz dowiedzieć się, która to podsieć i o której wersji IP mówimy. Należy również pamiętać, że z powodu NAT wykonywanego przez zaporę / routery adres IP interfejsu może nie być taki sam, jak zdalny host widzi przychodzące połączenie z komputera.
W przypadku fantazyjnego routingu źródła lub routingu według protokołu / portu może być trudno ustalić, który interfejs byłby używany do komunikowania się z jednym komputerem zdalnym za pośrednictwem danego protokołu, a nawet wtedy nie ma gwarancji, że adres IP tego interfejsu może być adresowany bezpośrednio przez komputer zdalny, który chce ustanowić nowe połączenie z komputerem.
W przypadku protokołu IPv4 (prawdopodobnie działa również w przypadku protokołu IPv6) sztuczką, która działa w wielu systemach unikatowych, w tym w systemie Linux, w celu znalezienia adresu IP interfejsu używanego do połączenia z danym hostem jest użycie metody connect (2) na gnieździe UDP i użycie metody getockname ():
Na przykład na moim komputerze domowym:
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]);'
Zostałby użyty do znalezienia adresu IP interfejsu, przez który osiągnęłbym 8.8.8.8 (serwer DNS Google). Zwraca coś w rodzaju „192.168.1.123”, który jest adresem interfejsu domyślnej trasy do Internetu. Jednak Google nie widziałby żądania DNS z mojego komputera jako przychodzącego z tego adresu IP, który jest prywatny, ponieważ NAT wykonuje mój domowy router szerokopasmowy.
connect () na gnieździe UDP nie wysyła żadnego pakietu (UDP nie wymaga połączenia), ale przygotowuje gniazdo, sprawdzając tablicę routingu.
ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')
ipa=$(hostname -i|cut -f2 -d ' ')
-I
zamiast -i
jest lepsze, ponieważ chcesz zignorować adresy sprzężenia zwrotnego, więc ostatecznym poleceniem byłobyipa=$(hostname -I|cut -f1 -d ' ')
grep
to nie wystarczy, nie podłączaj go do czegoś innego. Wystarczy użyć czegoś innego ( sed
, awk
, itd.).
Nie chcę być palantem, ale naprawdę jest właściwy sposób i to jest to. Obcinasz wyjście, ip route
aby uzyskać tylko źródłowy adres IP. W zależności od adresu IP, który próbujesz uzyskać, „mój własny adres IP” (słowa OP) będą różne. Jeśli zależy Ci na dostępie do publicznego Internetu, korzystanie z serwera DNS Google 8.8.8.8 jest dość standardowe. Więc...
ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
Jeśli chcę IP, którego używam, aby uzyskać dostęp do Internetu , używam tego:
pi@et3:~ $ ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
10.55.0.200
Jeśli chcę IP, którego używam, aby osiągnąć coś w mojej sieci VPN , używam tego:
pi@et3:~ $ ip route get 172.31.0.100 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
172.29.0.9
Ten następny jest naprawdę tylko w celach ilustracyjnych. Ale powinien działać na każdym systemie Linux. Możesz więc użyć tego do wykazania, że tak, wszystkie komputery mają wiele adresów IP przez cały czas.
Gdybym chciał, aby IP, z którego korzystam, osiągnąłbym siebie , użyłbym tego:
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
poleceniuPo pierwsze pozwól mi powiedzieć, że wybierając narzędzia uniksowe, próbujesz wybrać narzędzia, które wymagają najmniejszej liczby rur. Tak więc, choć niektóre odpowiedzi będzie rura ifconfig
do grep
do sed
do head
, że jest rzadko konieczne. Kiedy to zobaczysz, powinno podnieść czerwoną flagę, że korzystasz z porady kogoś z małym doświadczeniem. To nie czyni złego „rozwiązania”. Ale prawdopodobnie przydałoby się trochę usprawnienia.
Wybrałem, sed
ponieważ jest bardziej zwięzły niż ten sam przepływ pracy w awk
. (Mam od czasu awk przykład poniżej.) Nie sądzę, aby jakieś inne narzędzie, ale te 2 byłyby odpowiednie.
Sprawdźmy, co 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
Uwaga:
Kiedyś używałem, sed -n '/src/{s/.*src *//p;q}'
ale komentator zauważył, że niektóre systemy mają końcowe dane po src
polu.
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}}}'
Moje ifconfig
programy, które mam tun0
dla mojej sieci VPN i mojej sieci eth0
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}'
dał mi 10.1.2.3 uid 1002
. Dodam więc do append, | awk '{print $1}'
aby zachować tylko adres IP.
Na FreeBSD możesz użyć
dig +short `hostname -f`
Może to działać w innych środowiskach, w zależności od konfiguracji.
/etc/resolv.conf
i sposobu, w jaki router sieciowy obsługuje lokalne nazwy hostów. Można to wykorzystać w swoim środowisku, jeśli ją przetestujesz i działa. Ale jeśli to zrobisz, budujesz „kruchy” system, który spowoduje inne problemy, jeśli się nim podzielisz. Używaj ostrożnie.
Zakładając, że możesz mieć różne interfejsy o różnych nazwach, ale chcesz mieć pierwszy nielokalny host i inny niż ipv6, możesz spróbować:
ip=`ip addr show |grep "inet " |grep -v 127.0.0. |head -1|cut -d" " -f6|cut -d/ -f1`
Używam tego jednowarstwowego:
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-)
Używa ifconfig
(powszechnie dostępny), nie bierze localhost
adresu, nie wiąże cię z daną nazwą interfejsu, nie bierze pod uwagę IPv6 i próbuje uzyskać adres IP pierwszego dostępnego interfejsu sieciowego.
Powinieneś używać ip
(zamiast ifconfig
), ponieważ jest aktualny, utrzymywany, a być może co najważniejsze do celów skryptowych, daje spójne i możliwe do przetworzenia wyjście. Oto kilka podobnych podejść:
Jeśli chcesz mieć adres IPv4 dla swojego interfejsu Ethernet eth0
:
$ ip -4 -o addr show eth0 | awk '{print $4}'
192.168.1.166/24
Jako skrypt:
$ INTFC=eth0
$ MYIPV4=$(ip -4 -o addr show $INTFC | awk '{print $4}')
$ echo $MYIPV4
192.168.1.166/24
Dane wyjściowe wytworzone powyżej są zapisane w notacji CIDR. Jeśli notacja CIDR nie jest pożądana, można ją usunąć:
$ ip -4 -o addr show eth0 | awk '{print $4}' | cut -d "/" -f 1
192.168.1.166
Inna opcja, że IMHO jest „najbardziej elegancka”, otrzymuje adres IPv4 dla dowolnego interfejsu używanego do łączenia się z określonym zdalnym hostem (w tym przypadku 8.8.8.8). Dzięki uprzejmości @gatoatigrado w tej odpowiedzi :
$ ip route get 8.8.8.8 | awk '{ print $NF; exit }'
192.168.1.166
Jako skrypt:
$ RHOST=8.8.8.8
$ MYIP=$(ip route get $RHOST | awk '{ print $NF; exit }')
$ echo $MYIP
192.168.1.166
Działa to doskonale na hoście z jednym interfejsem, ale korzystniej działa również na hostach z wieloma interfejsami i / lub specyfikacjami tras.
ip
byłoby moim preferowanym podejściem, ale z pewnością nie jest to jedyny sposób na skórowanie tego kota. Oto inne podejście, które stosuje się, hostname
jeśli wolisz coś łatwiejszego / bardziej zwięzłego:
$ hostname --all-ip-addresses | awk '{print $1}'
Lub jeśli chcesz adres IPv6:
$ hostname --all-ip-addresses | awk '{print $2}'
Musiałem to zrobić w ramach aliasu, aby uruchomić serwer radiowy na mojej przewodowej karcie sieciowej. użyłem
ip addr | egrep -i "inet.+eth1" | awk -F[\ /] '{print $6}' | tr -d [:space:]
egrep
jest amortyzowane. Użyj grep -E
zamiast tego.
Niektóre polecenia działają na centos 6 lub 7, poniższe polecenie działa na obu,
#!/bin/sh
serverip=`/sbin/ifconfig eth0 | grep "inet" | awk '{print $2}' | awk 'NR==1' | cut -d':' -f2`
echo $serverip
grep | awk | awk
. linię można skrócić do/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
Ten fragment unika twardego kodowania nazwy urządzenia (np. „Eth0”) i użyje ip
zamiast ifconfig
:
/sbin/ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/'
Zwróci adres IP pierwszego aktywnego urządzenia wymienionego na wyjściu ip addr
. W zależności od komputera może to być adres ipv4 lub ipv6.
Aby zapisać go w zmiennej, użyj:
ip=$(/sbin/ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/')
wszystkie rozwiązania wykorzystujące awk / sed / grep wydają się zbyt skomplikowane i brzydkie jak na moją sytuację ... więc wymyśliłem to naprawdę proste rozwiązanie, ALE uważaj, ponieważ zawiera on pewne założenia, a mianowicie założenie, że OSTATNI interfejs jest tym, w którym jesteś zainteresowany. jeśli nie masz nic przeciwko, to jest to całkiem czyste:
ifconfig | awk '/net / { x = $2 } END { print x }'
w przeciwnym razie możesz zrobić jakieś głupie if
stwierdzenie, aby sprawdzić konkretny prefiks lub dowolne kryteria, jakie możesz mieć.
Jeśli szukasz publicznego adresu IP skrzynki , możesz użyć następujących opcji:
dig @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \"
Możesz użyć dig(1)
opcji takich jak -4
lub, -6
aby szukać adresu IPv4 lub IPv6; Google udzieli odpowiedzi w formie TXT
typu, która będzie zawierać cytaty, gdy zostaną przedstawione przez dig
; jeśli chcesz później użyć zmiennej z narzędziami takimi jak traceroute
, musisz użyć czegoś takiego jak tr (1), aby usunąć wspomniane cudzysłowy.
Inne opcje obejmują whoami.akamai.net
i myip.opendns.com
, które odpowiadają za pomocą A
i AAAA
zapisuje (zamiast TXT
jak w powyższym przykładzie od Google), więc nie wymagają usuwania cytatów:
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
Oto przykładowy skrypt, który wykorzystuje wszystkie powyższe opcje do ustawienia zmiennych:
#!/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}"
Jeśli szukasz prywatnego adresu IP lub zestawu wszystkich adresów IP przypisanych do skrzynki, możesz użyć kombinacji ifconfig
(na BSD i GNU / Linux), ip addr
(na GNU / Linux), hostname
(opcje -i
i -I
na GNU / Linux) i netstat
zobaczyć, co się dzieje.
hostname -I >> file_name
to zrobi wszystko, co chcesz
hostname: invalid option -- 'l'
...