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?
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?
Respostas:
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.
${var%.*}
man bashenter e, em seguida, digite /suffix patterne pressione enter. :)
new_var="${var%.*}.0"... nJoy !.
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
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 simplesi2d() faz o oposto - converte um número inteiro simples em um decimal pontilhadoipmask()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.