Заменить строку после последней точки в bash

12

У меня есть следующий шаблон в строке (IP-адрес):

123.444.888.235

Я хочу заменить последнее число после точки на 0, чтобы оно стало:

123.444.888.0

Как я могу сделать это на bashдругом языке сценариев оболочки?

Ari
источник
1
Где эти строки? В переменной bash? В текстовом файле по одному на строку?
Стефан Шазелас
Это в переменной. Я сожалею, забыл упомянуть об этом.
Ари
3
Если это IP-адреса, то 444 и 888 являются недопустимыми значениями октетов.
Цифровая травма

Ответы:

24

В любой оболочке POSIX:

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

${var%pattern}это оператор, введенный kshв 80-х годах, стандартизированный POSIX для стандартного shязыка и теперь реализованный всеми оболочками, интерпретирующими этот язык, в том числе bash.

${var%pattern}расширяется до содержимого $varобрезанной самой короткой строки, которая соответствует шаблону с конца его (или так же, как $varесли бы этот шаблон не соответствовал). Так ${var%.*}(где .*это шаблон , который означает дот следует любое количество символов) расширяется $varбез самой правой .и то , что следует за ним. В отличие от этого, ${var%%.*}когда самая длинная строка, соответствующая шаблону, будет удалена, она будет расширяться $varбез крайней левой части .и того, что следует за ней.

Стефан Шазелас
источник
Что такое ? ${var%.*}
голоса
@ tjt263, в командной строке введите man bashи нажмите ввод, затем введите /suffix patternи нажмите ввод. :)
Подстановочный
Добавил несколько цитат после вашего поста : new_var="${var%.*}.0"... nJoy !.
8

Это должно работать.

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

Обратите внимание, что последнее поле sedподстановки \10- это первый сопоставленный шаблон ( \1), объединенный с буквальным нулем.

Kira
источник
5

Несколько способов (все они предполагают, что вы хотите изменить последний набор чисел в строке):

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

Здесь, -F'.'говорит awkиспользовать .в качестве разделителя поля ввода и -vOFS='.'использовать его в качестве разделителя поля вывода. Тогда мы просто установить последнее поле ( $NF) в 0 и напечатать строку ( 1;это awkсокращение для «печати текущей строки»).

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

-pГоворит perlдля печати каждой строки ввода после применения сценария дается -e. Сам скрипт является простым оператором подстановки, который заменит одно или несколько чисел в конце строки на 0.

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

Та же идея в sedиспользовании [0-9]вместо \d.


Если ваша строка находится в переменной, и вы используете оболочку, которая поддерживает здесь строки (например, bashили, zshнапример), вы можете изменить выше:

awk -F'.' -vOFS='.' '{$NF=0}1;' <<<$var
perl -pe 's/\d+$/0/' <<<$var
sed 's/[0-9]*$/0/' <<<$var
Тердон
источник
5

Общий случай применения сетевой маски к IP-адресу:

Учитывая, что ваш ввод является IP-адресом, и вы заменяете последний октет этого адреса .0, то я предполагаю, что вы действительно пытаетесь достичь, это вычислить сетевую часть IP-адреса, используя 255.255.255.0маску сети.

Простая замена октетов нулями - это нормально, если длина вашей маски маски делится на 8, но это не общий случай. Если вам когда-нибудь понадобится выполнить эту операцию для любой действительной (подсетевой) маски сети, то вы можете сделать что-то вроде этого:

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

Это определяет 3 функции:

  • d2i() преобразует точечно-десятичную форму IP-адреса (или маски) в простое целое число
  • i2d() делает наоборот - конвертирует простое целое число в десятичную с точками
  • ipmask()просто вычисляет битовое И для адреса и маску сети, чтобы получить сетевую часть адреса. Баш ожидает, что операнды &будут целыми числами.

Два вызова ipmaskпоказывают, как сеть может быть рассчитана по IP-адресу для двух разных масок.


Обратите внимание, как указано в вопросе, 123.444.888.235это неверный IP-адрес. Я использовал 123.44.88.235вместо этого для этих примеров.

Цифровая травма
источник
0

Альтернативный sedответ:

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

Он группирует все до последней точки и заменяет всю строку содержимым группы, за которым следует 0.
Я использую -r, чтобы избежать необходимости избегать скобок.

Аарон
источник