Ersetzen Sie die Zeichenfolge nach dem letzten Punkt in der Bash

12

Ich habe das folgende Muster in einer Zeichenfolge (eine IP-Adresse):

123.444.888.235

Ich möchte die letzte Zahl nach dem Punkt durch ersetzen 0, damit es wird:

123.444.888.0

Wie könnte ich es in bashoder einer anderen Shell-Skriptsprache tun ?

Ari
quelle
1
Wo sind diese Saiten? In einer Bash-Variablen? In einer Textdatei eine pro Zeile?
Stéphane Chazelas
Es ist in einer Variablen. Es tut mir leid, dass ich vergessen habe, es zu erwähnen.
Ari
3
Wenn dies IP-Adressen sind, sind 444 und 888 ungültige Oktettwerte.
Digitales Trauma

Antworten:

22

In jeder POSIX-Shell:

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

${var%pattern}ist ein Operator, der kshin den 80er Jahren von POSIX für die Standardsprache standardisiert shund jetzt von allen Shells implementiert wurde, die diese Sprache interpretieren, einschließlich bash.

${var%pattern}Erweitert sich auf den Inhalt der $vargestrippten Zeichenfolge der kürzesten Zeichenfolge, die mit dem Muster am Ende übereinstimmt (oder auf den gleichen $varWert, als ob dieses Muster nicht übereinstimmt). Also ${var%.*}(wo .*ist ein Muster , das Punkt bedeutet, gefolgt von einer beliebigen Anzahl von Zeichen) wird $varohne das am weitesten rechts stehende .und was darauf folgt erweitert. Im Gegensatz dazu wird ${var%%.*}die längste Zeichenfolge, die mit dem Muster übereinstimmt, $varohne die am weitesten links stehende Zeichenfolge und die darauf folgenden Zeichenfolgen erweitert ..

Stéphane Chazelas
quelle
Was ist ? ${var%.*}
Stimmen
@ tjt263, geben Sie in der Befehlszeile ein und drücken Sie die Eingabetaste. Geben Sie man bashdann ein /suffix patternund drücken Sie die Eingabetaste. :)
Wildcard
Nach Ihrem Beitrag wurden einige Zitate hinzugefügt : new_var="${var%.*}.0"... nJoy!.
8

Das sollte funktionieren.

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

Beachten Sie, dass das letzte sedSubstitutionsfeld \10das erste übereinstimmende Muster ( \1) ist, das mit einer wörtlichen Null verkettet ist.

Kira
quelle
5

Einige Möglichkeiten (alle setzen voraus, dass Sie den letzten Satz von Zahlen in der Zeichenfolge ändern möchten):

$ echo 123.444.888.235 | awk -F'.' -vOFS='.' '{$NF=0}1;'
123.444.888.0

Hier wird angegeben, -F'.'dass awkes .als Eingabefeldtrennzeichen und -vOFS='.'als Ausgabefeldtrennzeichen verwendet werden soll. Dann setzen wir einfach das letzte Feld ( $NF) auf 0 und drucken Sie die Linie ( 1;ist eine awkAbkürzung für „die aktuelle Zeile drucken“).

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

Das -psagt perl, dass jede Eingabezeile gedruckt werden soll, nachdem das von gegebene Skript angewendet wurde -e. Das Skript selbst ist nur ein einfacher Substitutionsoperator, der eine oder mehrere Zahlen am Ende der Zeile durch ersetzt 0.

$ echo 123.444.888.235 | sed 's/[0-9]*$/0/'
123.444.888.0

Die gleiche Idee in sed, mit [0-9]anstelle von \d.


Wenn sich Ihre Zeichenfolge in einer Variablen befindet und Sie eine Shell verwenden, die hier Zeichenfolgen unterstützt (wie z. B. bashoder zsh), können Sie Folgendes ändern:

awk -F'.' -vOFS='.' '{$NF=0}1;' <<<$var
perl -pe 's/\d+$/0/' <<<$var
sed 's/[0-9]*$/0/' <<<$var
terdon
quelle
5

Allgemeiner Fall für das Anwenden einer Netzmaske auf eine IP-Adresse:

Angesichts der Tatsache, dass Ihre Eingabe eine IP-Adresse ist und Sie das letzte Oktett dieser Adresse durch ersetzen .0, gehe ich davon aus, dass Sie wirklich versuchen, den Netzwerkanteil der IP-Adresse mithilfe der 255.255.255.0Netzmaske zu berechnen .

Das einfache Ersetzen von Oktetten durch Nullen ist in Ordnung, wenn Ihre Netzmaskenlänge durch 8 teilbar ist, dies ist jedoch nicht der allgemeine Fall. Wenn Sie diesen Vorgang jemals für eine gültige (Subnetz-) Netzmaske ausführen müssen, können Sie Folgendes tun:

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

Dies definiert 3 Funktionen:

  • d2i() konvertiert die Punkt-Dezimal-Form einer IP-Adresse (oder Maske) in eine einfache Ganzzahl
  • i2d() macht das Gegenteil - konvertiert eine einfache Ganzzahl in eine gepunktete Dezimalstelle
  • ipmask()Berechnet einfach ein bitweises UND einer Adresse und einer Netzmaske, um den Netzwerkteil einer Adresse anzugeben. Bash erwartet, dass die Operanden von &ganze Zahlen sind.

Die beiden Aufrufe ipmaskzeigen, wie das Netzwerk aus einer IP-Adresse für zwei verschiedene Masken berechnet werden kann.


Beachten Sie, wie in der Frage angegeben, 123.444.888.235eine ungültige IP-Adresse. Ich habe 123.44.88.235stattdessen für diese Beispiele verwendet.

Digitales Trauma
quelle
0

Eine alternative sedAntwort:

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

Es gruppiert alles bis zum letzten Punkt und ersetzt die vollständige Zeile durch den Inhalt der Gruppe, gefolgt von 0.
Ich verwende -r, um zu vermeiden, dass Klammern ausgeblendet werden müssen.

Aaron
quelle