Zamień ciąg po ostatniej kropce w bash

12

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 bashinnym języku skryptowym powłoki?

Ari
źródło
1
Gdzie są te struny? W zmiennej bash? W pliku tekstowym po jednym w wierszu?
Stéphane Chazelas,
Jest w zmiennej. Przepraszam, zapomniałem o tym wspomnieć.
Ari
3
Jeśli są to adresy IP, wówczas 444 i 888 są niepoprawnymi wartościami oktetów.
Cyfrowy uraz

Odpowiedzi:

24

W dowolnej powłoce POSIX:

var=123.444.888.235
new_var="${var%.*}.0"

${var%pattern}jest operatorem wprowadzonym kshw latach 80., znormalizowanym przez POSIX dla standardowego shjęzyka i teraz zaimplementowanym przez wszystkie powłoki, które interpretują ten język, w tym bash.

${var%pattern}rozwija się do zawartości $varpozbawionego najkrótszego łańcucha, który pasuje do wzorca na jego końcu (lub do tego samego, $varjakby 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ę $varbez 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ę $varbez skrajnego lewego .i tego, co następuje po nim.

Stéphane Chazelas
źródło
Co to jest ? ${var%.*}
głosy
@ tjt263, w linii poleceń wpisz man bashi naciśnij enter, następnie wpisz /suffix patterni naciśnij enter. :)
Wildcard,
Dodano kilka cytatów po Twoim poście : new_var="${var%.*}.0"... nJoy !.
8

To powinno działać.

echo 123.444.888.235 | sed 's/\([0-9]*\.[0-9]*\.[0-9]*\.\)[0-9]*/\10/'

Zauważ, że ostatnim polem sedpodstawienia \10jest pierwszy dopasowany wzorzec ( \1), połączony dosłownie zerem.

Kira
źródło
5

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, awkaby 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 awkskrót od „print the current line”).

$ echo 123.444.888.235 | perl -pe 's/\d+$/0/'
123.444.888.0

-pMówi perlwydrukować 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 bashlub zshna 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
terdon
źródło
5

Ogólny przypadek zastosowania maski sieci do adresu IP:

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.0maski 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 ipmaskpokazują, jak można obliczyć sieć z adresu IP dla dwóch różnych masek.


Uwaga: jak podano w pytaniu, 123.444.888.235to nieprawidłowy adres IP. Użyłem 123.44.88.235zamiast tego dla tych przykładów.

Cyfrowa trauma
źródło
0

Alternatywna sedodpowiedź:

sed -r 's/(.*\.).*/\10/'

Grupuje wszystko do ostatniej kropki i zastępuje pełną linię treścią grupy, po której następuje 0.
Używam -r, aby uniknąć konieczności ucieczki w nawiasy.

Aaron
źródło