J'ai le model suivant dans une string (une adresse IP):
123.444.888.235
Je veux replace le dernier numéro après le point par 0
, alors il devient:
123.444.888.0
Comment pourrais-je le faire dans bash
ou un autre langage de script shell?
Dans n'importe quel shell POSIX:
var=123.444.888.235 new_var="${var%.*}.0"
${var%pattern}
est un opérateur introduit par ksh
dans les années 80, standardisé par POSIX pour le langage sh
standard et maintenant implémenté par tous les shells qui interprètent ce langage, y compris bash
.
${var%pattern}
développe le contenu de $var
dépouillé de la string la plus courte qui correspond à la fin du pattern (ou au même que $var
si ce model ne correspond pas). Donc ${var%.*}
(Où .*
Est un motif qui signifie point suivi d'un nombre quelconque de caractères) se développe à $var
sans le plus à droite .
et ce qui suit. En revanche, ${var%%.*}
Où la string la plus longue qui correspond au model est supprimée s'élargira à $var
sans le plus à gauche .
et ce qui suit.
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 substitution sed
, \10
, est le premier motif apparié ( \1
), concaténé avec un zéro littéral.
Quelques façons (toutes supposent que vous voulez changer le dernier set de nombres dans la string):
$ echo 123.444.888.235 | awk -F'.' -vOFS='.' '{$NF=0}1;' 123.444.888.0
Ici, -F'.'
dit awk
à utiliser .
comme séparateur de champs d'input et -vOFS='.'
pour l'utiliser comme séparateur de champ de sortie. Ensuite, nous définissons simplement le dernier champ ( $NF
) sur 0 et imprimons la ligne ( 1;
abréviation awk
pour «imprimer la ligne en cours»).
$ echo 123.444.888.235 | perl -pe 's/\d+$/0/' 123.444.888.0
Le -p
indique à perl
d'imprimer chaque ligne d'input après avoir appliqué le script donné par -e
. Le script lui-même est juste un simple opérateur de substitution qui replacea 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 string est dans une variable et que vous utilisez un shell qui supporte ici les strings (comme bash
ou zsh
par exemple), vous pouvez changer le ci-dessus en:
awk -F'.' -vOFS='.' '{$NF=0}1;' <<<$var perl -pe 's/\d+$/0/' <<<$var sed 's/[0-9]*$/0/' <<<$var
Étant donné que votre input est une adresse IP et que vous remplacez le dernier octet de cette adresse par .0
, je suppose que ce que vous essayez vraiment d'get est de calculer la partie réseau de l'adresse IP en utilisant le 255.255.255.0
masque de réseau.
Il suffit de replace les octets par des zéros si la longueur de votre masque est divisible par 8, mais ce n'est pas le cas général. Si vous avez besoin d'effectuer cette opération pour n'importe quel masque de 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 pointée d'une adresse IP (ou masque) en un entier simple i2d()
fait le contraire – convertit un entier simple en un point décimal en pointillés ipmask()
calcule simplement un bit ET 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 à ipmask
montrent comment le réseau peut être calculé à partir d'une adresse IP pour deux masques différents.
Note comme indiqué dans la question, 123.444.888.235
est une adresse IP non valide. J'ai utilisé 123.44.88.235
place de ces exemples.
Une réponse sed
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 aux parenthèses.