Remplacer la chaîne après le dernier point de bash

12

J'ai le modèle suivant dans une chaîne (une adresse IP):

123.444.888.235

Je veux remplacer le dernier numéro après le point par 0, il devient donc:

123.444.888.0

Comment pourrais-je le faire dans bashun autre langage de script shell?

Ari
la source
1
Où sont ces cordes? Dans une variable bash? Dans un fichier texte un par ligne?
Stéphane Chazelas
C'est dans une variable. Je suis désolé d'avoir oublié de le mentionner.
Ari
3
S'il s'agit d'adresses IP, alors 444 et 888 sont des valeurs d'octet invalides.
Digital Trauma

Réponses:

24

Dans n'importe quel shell POSIX:

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

${var%pattern}est un opérateur introduit par kshdans les années 80, normalisé par POSIX pour le shlangage standard et maintenant implémenté par tous les shells qui interprètent ce langage, notamment bash.

${var%pattern}se développe au contenu de $vardépouillé de la chaîne la plus courte qui correspond au modèle à la fin de celui-ci (ou au même que $varsi ce modèle ne correspond pas). Donc ${var%.*}(où .*est un motif qui signifie un point suivi d'un nombre quelconque de caractères) se développe $varsans le plus à droite .et ce qui le suit. En revanche, ${var%%.*}là où la chaîne la plus longue qui correspond au modèle est supprimée, elle se développerait $varsans le plus à gauche .et ce qui suit.

Stéphane Chazelas
la source
Qu'est-ce que c'est ? ${var%.*}
voix
@ tjt263, sur la ligne de commande, tapez man bashet appuyez sur entrée, puis tapez /suffix patternet appuyez sur entrée. :)
Wildcard
Ajout de quelques citations après votre message : new_var="${var%.*}.0"... nJoy !.
8

Cela devrait fonctionner.

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

Notez que le dernier champ de sedsubstitution,, \10est le premier motif apparié ( \1), concaténé avec un zéro littéral.

Kira
la source
5

Quelques façons (elles supposent toutes que vous souhaitez modifier le dernier ensemble de nombres de la chaîne):

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

Ici, -F'.'indique awkd'utiliser .comme séparateur de champ d'entrée et -vOFS='.'de l'utiliser comme séparateur de champ de sortie. Ensuite, nous mettons simplement le dernier champ ( $NF) à 0 et imprimons la ligne ( 1;est un awkraccourci pour "imprimer la ligne actuelle").

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

Le -pdit perld'imprimer chaque ligne d'entrée après avoir appliqué le script donné par -e. Le script lui-même n'est qu'un simple opérateur de substitution qui remplacera un ou plusieurs nombres à la fin de la ligne par 0.

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

La même idée dans sed, en utilisant [0-9]au lieu de \d.


Si votre chaîne est dans une variable et que vous utilisez un shell qui prend en charge ici les chaînes (telles que bashou zshpar exemple), vous pouvez changer ce qui précède en:

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

Cas général d'application d'un masque de réseau à une adresse IP:

Étant donné que votre entrée est une adresse IP et que vous remplacez le dernier octet de cette adresse .0, je suppose que ce que vous essayez vraiment de réaliser est de calculer la partie réseau de l'adresse IP à l'aide du 255.255.255.0masque de réseau.

Remplacer simplement des octets par des zéros est OK si la longueur de votre masque de réseau est divisible par 8, mais ce n'est pas le cas général. Si vous devez effectuer cette opération pour n'importe quel masque de sous-réseau valide (sous-réseau), vous pouvez faire quelque chose comme ceci:

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

Cela définit 3 fonctions:

  • d2i() convertit la forme décimale en pointillés d'une adresse IP (ou d'un masque) en un entier simple
  • i2d() fait le contraire - convertit un entier simple en une décimale en pointillés
  • ipmask()calcule simplement un ET au niveau du bit d'une adresse et d'un masque de réseau pour donner la partie réseau d'une adresse. Bash s'attend à ce que les opérandes de &soient des entiers.

Les deux appels ipmaskmontrent comment le réseau peut être calculé à partir d'une adresse IP pour deux masques différents.


Remarque, comme indiqué dans la question, 123.444.888.235est une adresse IP non valide. J'ai utilisé à la 123.44.88.235place pour ces exemples.

Traumatisme numérique
la source
0

Une sedréponse alternative :

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

Il regroupe tout jusqu'au dernier point et remplace la ligne complète par le contenu du groupe suivi de 0.
J'utilise -r pour éviter d'avoir à échapper les parenthèses.

Aaron
la source