Nie najłatwiej , ale możesz zrobić coś takiego:
$ IP=109.96.77.15
$ echo "$((${-+"(${IP//./"+256*("}))))"}&255))"
109
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>8&255))"
96
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>16&255))"
77
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>24&255))"
15
To powinno działać w ksh93 (jeżeli ${var//pattern/replacement}
operator pochodzi), bash
4.3+, BusyBox sh
, yash
, mksh
i zsh
, choć oczywiście w zsh
nie są o wiele prostsze sposoby . W starszych wersjach bash
trzeba by usunąć wewnętrzne cytaty. Działa z tymi wewnętrznymi cudzysłowami usuniętymi również w większości innych powłok, ale nie w ksh93.
Zakłada się, że $IP
zawiera prawidłową reprezentację adresu IPv4 w postaci dziesiętno-dziesiętnej (choć działałoby to również w przypadku reprezentacji cztero-szesnastkowych, takich jak 0x6d.0x60.0x4d.0xf
(a nawet ósemkowa w niektórych powłokach), ale wyświetlałby wartości dziesiętnie). Jeśli zawartość $IP
pochodzi z niezaufanego źródła, oznacza to lukę w zabezpieczeniach polegającą na wstrzykiwaniu poleceń.
Zasadniczo, jak jesteśmy zastępując każdy .
w $IP
z +256*(
, skończymy oceny:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
Więc jesteśmy konstruowania 32 bitową liczbę całkowitą z tych 4 bajtów, takich jak adres IPv4 ostatecznie jest (choć z bajty odwrócone) ¹, a następnie przy użyciu >>
, &
bitowe operatorów wyodrębnić odpowiednie bajty.
Używamy ${param+value}
standardowego operatora (tutaj $-
zawsze gwarantuje się ustawienie) zamiast tego, value
ponieważ w przeciwnym razie parser arytmetyczny narzekałby na niedopasowany nawias. Powłoka tutaj może znaleźć zamknięcie ))
dla otwarcia $((
, a następnie wykonać rozszerzenia wewnątrz, które spowodują wyrażenie arytmetyczne do oceny.
Dzięki $(((${IP//./"+256*("}))))&255))
zamiast, powłoka potraktuje drugi i trzeci )
s tam jako zamknięcie ))
dla $((
i zgłosić błąd składni.
W ksh93 możesz także:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
, mksh
, zsh
Zostały skopiowane ksh93 męska ${var/pattern/replacement}
operatora, ale nie, że grupa przechwytywania obsługi część. zsh
obsługuje go z inną składnią:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
obsługuje pewną formę obsługi grup przechwytywania w operatorze dopasowania wyrażeń regularnych , ale nie w ${var/pattern/replacement}
.
POSIXly użyłbyś:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
noglob
Aby uniknąć złych niespodzianek dla wartości $IP
jak 10.*.*.*
, podpowłoki aby ograniczyć zakres tych zmian do opcji i $IFS
.
¹ Adres IPv4 to tylko 32-bitowa liczba całkowita, a na przykład 127.0.0.1 to tylko jedna z wielu (choć najczęstszych) reprezentacji tekstowych. Ten sam typowy adres IPv4 interfejsu sprzężenia zwrotnego można również przedstawić jako 0x7f000001 lub 127.1 (być może bardziej odpowiedni tutaj, aby powiedzieć, że jest to 1
adres w sieci klasy 127.0 / 8 klasy A) lub 0177.0.1, lub inne kombinacje 1 do 4 liczb wyrażonych jako liczba ósemkowa, dziesiętna lub szesnastkowa. Możesz przekazać je wszystkim, ping
na przykład, a zobaczysz, że wszystkie będą pingować localhost.
Jeśli nie przeszkadza ci efekt uboczny ustawiania dowolnej zmiennej tymczasowej (tutaj $n
), w bash
lub ksh93
lub zsh -o octalzeroes
lub lksh -o posix
, możesz po prostu przekonwertować wszystkie te reprezentacje z powrotem na 32-bitową liczbę całkowitą za pomocą:
$((n=32,(${IP//./"<<(n-=8))+("})))
A następnie wyodrębnij wszystkie składniki za pomocą >>
/ &
kombinacji takich jak powyżej.
$ IP=0x7f000001
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ IP=127.1
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ echo "$((n=32,((${IP//./"<<(n-=8))+("}))>>24&255))"
127
$ perl -MSocket -le 'print unpack("L>", inet_aton("127.0.0.1"))'
2130706433
mksh
używa 32-bitowych liczb całkowitych ze znakiem dla wyrażeń arytmetycznych, można $((# n=32,...))
tam użyć , aby wymusić użycie 32-bitowych liczb bez znaku (i posix
opcję rozpoznawania stałych ósemkowych).
IFS
naread
tam:IFS=. read -a ArrIP<<<"$IP"