Sostituisci la stringa dopo l'ultimo punto in bash


12

Ho il seguente modello in una stringa (un indirizzo IP):

123.444.888.235

Voglio sostituire l'ultimo numero dopo il punto con 0, quindi diventa:

123.444.888.0

Come potrei farlo in bashun altro linguaggio di script di shell?


1
Dove sono quelle corde? In una variabile bash? In un file di testo uno per riga?
Stéphane Chazelas,

È in una variabile. Mi dispiace è stato dimenticato di menzionarlo.
Ari,

3
Se si tratta di indirizzi IP, 444 e 888 sono valori di ottetti non validi.
Digital Trauma,

Risposte:


24

In qualsiasi shell POSIX:

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

${var%pattern}è un operatore introdotto kshnegli anni '80, standardizzato da POSIX per il shlinguaggio standard e ora implementato da tutte le shell che interpretano quel linguaggio, incluso bash.

${var%pattern}si espande al contenuto di $varstripped della stringa più corta che corrisponde al pattern alla fine di esso (o allo stesso modo in cui $vartale pattern non corrisponde). Quindi ${var%.*}(dove .*è un modello che significa punto seguito da un numero qualsiasi di caratteri) si espande $varsenza il più a destra .e cosa lo segue. Al contrario, ${var%%.*}dove viene spogliata la stringa più lunga che corrisponde al modello si espanderebbe $varsenza quella più a sinistra .e ciò che segue.


Che cosa è ? ${var%.*}
voci

@ tjt263, alla riga di comando digitare man bashe premere invio, quindi digitare /suffix patterne premere invio . :)
Wildcard il

Aggiunte alcune citazioni dopo il tuo post : new_var="${var%.*}.0"... nJoy !.

8

Questo dovrebbe funzionare.

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

Si noti che l'ultimo campo di sedsostituzione, \10è il primo modello corrispondente ( \1), concatenato con uno zero letterale.


5

Alcuni modi (tutti presuppongono che si desideri modificare l'ultimo set di numeri nella stringa):

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

Qui, -F'.'dice awkdi usare .come separatore del campo di input e -vOFS='.'di usarlo come separatore del campo di output. Quindi, impostiamo semplicemente l'ultimo campo ( $NF) su 0 e stampiamo la linea ( 1;è la awkscorciatoia per "stampare la linea corrente").

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

La -pdice perlper stampare ogni linea di ingresso dopo l'applicazione dello script data dal -e. Lo script stesso è solo un semplice operatore di sostituzione che sostituirà uno o più numeri alla fine della riga 0.

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

La stessa idea in sed, usando [0-9]invece di \d.


Se la tua stringa è in una variabile e usi una shell che supporta stringhe qui (come basho zshper esempio), puoi cambiare quanto sopra in:

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

5

Caso generale per l'applicazione di una maschera di rete a un indirizzo IP:

Dato che il tuo input è un indirizzo IP e che stai sostituendo l'ultimo ottetto di quell'indirizzo .0, suppongo che ciò che stai veramente cercando di ottenere sia calcolare la porzione di rete dell'indirizzo IP, usando la 255.255.255.0maschera di rete.

La semplice sostituzione di ottetti con zero è OK se la lunghezza della maschera di rete è divisibile per 8, ma non è questo il caso generale. Se hai mai bisogno di eseguire questa operazione per qualsiasi maschera di rete (sottorete) valida, puoi fare qualcosa del genere:

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

Questo definisce 3 funzioni:

  • d2i() converte la forma decimale puntata di un indirizzo IP (o maschera) in un intero semplice
  • i2d() fa il contrario: converte un intero semplice in un decimale puntato
  • ipmask()calcola semplicemente un AND bit a bit di un indirizzo e una maschera di rete per fornire la porzione di rete di un indirizzo. Bash prevede che gli operandi &siano numeri interi.

Le due chiamate per ipmaskmostrare come la rete può essere calcolata da un indirizzo IP per due diverse maschere.


Nota come indicato nella domanda, 123.444.888.235è un indirizzo IP non valido. Ho usato 123.44.88.235invece per questi esempi.


0

Una sedrisposta alternativa :

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

Raggruppa tutto fino all'ultimo punto e sostituisce la riga completa con il contenuto del gruppo seguito da 0.
Uso -r per evitare di sfuggire alle parentesi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.