Substituir sequência após o último ponto no bash


12

Eu tenho o seguinte padrão em uma string (um endereço IP):

123.444.888.235

Quero substituir o último número após o ponto por 0, para que ele se torne:

123.444.888.0

Como eu poderia fazer isso em bashoutra linguagem de script de shell?


1
Onde estão essas cordas? Em uma variável bash? Em um arquivo de texto, um por linha?
Stéphane Chazelas

Está em uma variável. Lamento ter esquecido de mencionar.
Ari #

3
Se esses são endereços IP, 444 e 888 são valores de octetos inválidos.
Digital Trauma

Respostas:


24

Em qualquer shell POSIX:

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

${var%pattern}é um operador introduzido kshnos anos 80, padronizado pelo POSIX para o shidioma padrão e agora implementado por todos os shells que interpretam esse idioma, inclusive bash.

${var%pattern}expande para o conteúdo de $varstripped da string mais curta que corresponde ao padrão no final dela (ou para o mesmo que $varse esse padrão não corresponder). Então ${var%.*}(onde .*está um padrão que significa ponto seguido por qualquer número de caracteres) se expande $varsem o mais à direita .e o que se segue. Por outro lado, ${var%%.*}onde a string mais longa que corresponde ao padrão é removida, ela se expandirá para $varsem a mais à esquerda .e o que segue.


O que é ? ${var%.*}
vozes

@ tjt263, na linha de comando, digite man bashenter e, em seguida, digite /suffix patterne pressione enter. :)
Curinga

Adicionadas algumas citações após a sua postagem : new_var="${var%.*}.0"... nJoy !.

8

Isso deve funcionar.

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

Observe que o último campo de sedsubstituição,, \10é o primeiro padrão correspondente ( \1), concatenado com um zero literal.


5

Algumas maneiras (todas elas assumem que você deseja alterar o último conjunto de números na cadeia de caracteres):

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

Aqui, -F'.'diz awkpara usar .como separador de campos de entrada e -vOFS='.'para usá-lo como separador de campos de saída. Em seguida, basta definir o último campo ( $NF) para 0 e imprimir a linha ( 1;é uma awkabreviação de "print the current line").

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

O -pdiz perlpara imprimir cada linha de entrada depois de aplicar o script fornecido por -e. O script em si é apenas um operador de substituição simples que substituirá um ou mais números no final da linha por 0.

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

A mesma idéia em sed, usando em [0-9]vez de \d.


Se sua string estiver em uma variável e você usar um shell que suporte aqui strings (como bashou zshpor exemplo), você poderá alterar o acima para:

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

5

Caso geral para aplicar uma máscara de rede a um endereço IP:

Dado que sua entrada é um endereço IP e que você está substituindo o último octeto desse endereço .0, suponho que o que você realmente está tentando obter é calcular a parte da rede do endereço IP, usando a 255.255.255.0máscara de rede.

Simplesmente substituir octetos por zeros é bom se o comprimento da sua máscara de rede é divisível por 8, mas esse não é o caso geral. Se você precisar executar esta operação para qualquer máscara de rede (sub-rede) válida, poderá fazer algo assim:

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

Isso define três funções:

  • d2i() converte a forma decimal pontilhada de um endereço IP (ou máscara) em um número inteiro simples
  • i2d() faz o oposto - converte um número inteiro simples em um decimal pontilhado
  • ipmask()simplesmente calcula um E bit a bit de um endereço e uma máscara de rede para fornecer a parte de rede de um endereço. O Bash espera que os operandos &sejam inteiros.

As duas chamadas ipmaskmostram como a rede pode ser calculada a partir de um endereço IP para duas máscaras diferentes.


Observe como indicado na pergunta, 123.444.888.235é um endereço IP inválido. Eu usei 123.44.88.235esses exemplos.


0

Uma sedresposta alternativa :

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

Ele agrupa tudo até o último ponto e substitui a linha completa pelo conteúdo do grupo seguido por 0.
Eu uso -r para evitar ter que escapar parênteses.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.