Mam następujący ciąg w ciągu (adres IP):
123.444.888.235
Chcę zastąpić ostatni numer po kropce 0
, więc staje się:
123.444.888.0
Jak mogę to zrobić w bash
innym języku skryptowym powłoki?
Mam następujący ciąg w ciągu (adres IP):
123.444.888.235
Chcę zastąpić ostatni numer po kropce 0
, więc staje się:
123.444.888.0
Jak mogę to zrobić w bash
innym języku skryptowym powłoki?
Odpowiedzi:
W dowolnej powłoce POSIX:
var=123.444.888.235
new_var="${var%.*}.0"
${var%pattern}
jest operatorem wprowadzonym ksh
w latach 80., znormalizowanym przez POSIX dla standardowego sh
języka i teraz zaimplementowanym przez wszystkie powłoki, które interpretują ten język, w tym bash
.
${var%pattern}
rozwija się do zawartości $var
pozbawionego najkrótszego łańcucha, który pasuje do wzorca na jego końcu (lub do tego samego, $var
jakby ten wzór nie pasował). Tak więc ${var%.*}
(gdzie .*
jest wzorzec oznaczający kropkę, po której następuje dowolna liczba znaków) rozwija się $var
bez znaku najbardziej po prawej .
i co następuje po nim. W przeciwieństwie do tego, ${var%%.*}
gdy najdłuższy ciąg pasujący do wzoru zostanie rozebrany, rozwinąłby się $var
bez skrajnego lewego .
i tego, co następuje po nim.
${var%.*}
man bash
i naciśnij enter, następnie wpisz /suffix pattern
i naciśnij enter. :)
new_var="${var%.*}.0"
... nJoy !.
Kilka sposobów (wszystkie zakładają, że chcesz zmienić ostatni zestaw liczb w ciągu):
$ echo 123.444.888.235 | awk -F'.' -vOFS='.' '{$NF=0}1;'
123.444.888.0
Tutaj -F'.'
mówi, awk
aby użyć .
jako separatora pola wejściowego i -vOFS='.'
użyć go jako separatora pola wyjściowego. Następnie po prostu ustawiamy ostatnie pole ( $NF
) na 0 i wypisujemy linię ( 1;
to awk
skrót od „print the current line”).
$ echo 123.444.888.235 | perl -pe 's/\d+$/0/'
123.444.888.0
-p
Mówi perl
wydrukować każdą linię wejściowego po zastosowaniu skryptu podane przez -e
. Sam skrypt jest po prostu prostym operatorem podstawiania, który zastąpi jedną lub więcej liczb na końcu wiersza 0
.
$ echo 123.444.888.235 | sed 's/[0-9]*$/0/'
123.444.888.0
Ten sam pomysł w sed
, używając [0-9]
zamiast \d
.
Jeśli twój ciąg jest w zmiennej i używasz powłoki, która obsługuje tutaj ciągi (takie jak bash
lub zsh
na przykład), możesz zmienić powyższe na:
awk -F'.' -vOFS='.' '{$NF=0}1;' <<<$var
perl -pe 's/\d+$/0/' <<<$var
sed 's/[0-9]*$/0/' <<<$var
Biorąc pod uwagę, że wpisujesz adres IP i zastępujesz ostatni oktet tego adresu .0
, zakładam, że naprawdę próbujesz obliczyć część sieciową adresu IP za pomocą 255.255.255.0
maski sieci.
Zwykłe zastąpienie oktetów zerami jest OK, jeśli długość maski sieci jest podzielna przez 8, ale nie jest to ogólny przypadek. Jeśli kiedykolwiek będziesz musiał wykonać tę operację dla dowolnej prawidłowej maski sieci (podsieci), możesz zrobić coś takiego:
function d2i() {
echo $(( 0x$( printf "%02x" ${1//./ } ) ))
}
function i2d() {
h=$( printf "%08X" "$1" )
echo $(( 0x${h:0:2} )).$(( 0x${h:2:2} )).$(( 0x${h:4:2} )).$(( 0x${h:6:2} ))
}
function ipmask() {
i2d $(( $( d2i $1 ) & $( d2i $2 ) ))
}
ipmask 123.44.88.235 255.255.255.0 # outputs 123.44.88.0
ipmask 123.44.88.235 255.255.255.240 # outputs 123.44.88.224
Definiuje to 3 funkcje:
d2i()
konwertuje kropkowo-dziesiętną postać adresu IP (lub maski) na prostą liczbę całkowitąi2d()
robi coś przeciwnego - konwertuje zwykłą liczbę całkowitą na kropkę dziesiętnąipmask()
po prostu oblicza bitowo ORAZ adresu i maski sieci, aby podać część adresu w sieci. Bash oczekuje, że operandy &
będą liczbami całkowitymi.Dwa połączenia ipmask
pokazują, jak można obliczyć sieć z adresu IP dla dwóch różnych masek.
Uwaga: jak podano w pytaniu, 123.444.888.235
to nieprawidłowy adres IP. Użyłem 123.44.88.235
zamiast tego dla tych przykładów.