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 bash
outra 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 bash
outra linguagem de script de shell?
Respostas:
Em qualquer shell POSIX:
var=123.444.888.235
new_var="${var%.*}.0"
${var%pattern}
é um operador introduzido ksh
nos anos 80, padronizado pelo POSIX para o sh
idioma padrão e agora implementado por todos os shells que interpretam esse idioma, inclusive bash
.
${var%pattern}
expande para o conteúdo de $var
stripped da string mais curta que corresponde ao padrão no final dela (ou para o mesmo que $var
se 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 $var
sem 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 $var
sem a mais à esquerda .
e o que segue.
${var%.*}
man bash
enter e, em seguida, digite /suffix pattern
e 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 awk
para 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 awk
abreviação de "print the current line").
$ echo 123.444.888.235 | perl -pe 's/\d+$/0/'
123.444.888.0
O -p
diz perl
para 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 bash
ou zsh
por 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.0
má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 ipmask
mostram 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.235
esses exemplos.