Четыре раза заменить на sed

Я нашел две части информации в сети stackexchange, которые помогли мне прийти к этому рабочему ответу:

Однако код в этом ответе - мой собственный.

Посмотрите историю правок, если хотите больше многословия; я вырезал все лишнее и "шаги по пути".


Я думаю, что лучший способ:

center() {
  termwidth="$(tput cols)"
  padding="$(printf '%0.1s' ={1..500})"
  printf '%*.*s %s %*.*s\n' 0 "$(((termwidth-2-${#1})/2))" "$padding" "$1" 0 "$(((termwidth-1-${#1})/2))" "$padding"
}
center "Something I want to print"

Вывод на терминал шириной 80 колонок:

========================== Something I want to print ===========================

Обратите внимание, что вставка не обязательно должна быть одним символом; на самом деле переменная padding таковой не является, в приведенном выше коде она длиной 500 символов. Вы можете использовать другую форму вставки, изменив только строку padding:

padding="$(printf '%0.2s' ^v{1..500})"

Результат в:

^v^v^v^v^v^v^v^v^v^v^v^v^v Something I want to print ^v^v^v^v^v^v^v^v^v^v^v^v^v^

Еще одно удобное использование:

clear && center "This is my header"

3
18.03.2019, 05:14
4 ответа

Ваши данные состоят из шести;-полей с разделителями, и вы хотите заменить точки в полях со 2 по 5 (, а не 1 или 6 )запятыми.

Это проще всего сделать с помощьюawk:

awk -F ';' 'BEGIN { OFS=FS } { for (i=2; i<=5; ++i) gsub("\\.", ",", $i); print }' file

С приведенными примерными данными получается

2019-03-17T11:32:28.143343Z;1234,5678;901,234;567,89012;3456,78;192.168.0.1

Код просто выполняет итерацию полей с разделителями;-каждой строки ввода и вызывает gsub()для выполнения глобального поиска и замены (, как вы сделали бы с s/\./,/gили y/./,/вsed)на отдельные поля, по которым повторяется цикл.

Затем распечатывается измененная строка.

Опция -Fустанавливает разделитель полей ввода в виде точки с запятой, и мы используем блок BEGIN, чтобы также установить разделитель полей вывода на то же значение (, что в противном случае вы получили бы поля, разделенные пробелом -).


Используя sed, вы можете сделать что-то вроде

sed 's/\./,/2; s/\./,/2; s/\./,/2; s/\./,/2' file

То есть, замените 2-ю точку четыре раза (, какая из них является 2-й точкой, будет меняться при каждой замене, поскольку вы заменяете их ). Однако это предполагает, что количество значений в каждом поле остается постоянным.

Чтобы обойти эту проблему, если в какой-то момент у вас есть более двух -точек, разделенных полем, вы можете

sed 'h; s/^[^;]*;//; s/;[^;]*$//; y/./,/; G;H;x; s/;[^\n]*\n/;/; s/\n.*;/;/' file

Короче говоря, эти команды выполняют

  1. Скопируйте исходную строку в область хранения.
  2. Удалить первое и последнее поля в пространстве шаблонов.
  3. Замените все точки на запятые в пространстве шаблонов (, это команда y). Все точки, которые должны были превратиться в запятые, теперь изменены. Теперь мы должны собрать строку из среднего бита в пространстве шаблонов и исходных данных в пространстве хранения.
  4. Создайте (с помощью G;H;x), чтобы пространство шаблонов содержало

    .
    1. Исходная строка, за которой следует новая строка,
    2. Модифицированный средний бит, за которым следует новая строка
    3. Снова исходная строка.
  5. Итак, теперь пространство шаблонов содержит три строки . Удалите все, кроме первого поля в первой строке и новой строки, и замените этот удаленный бит на ;.

  6. Сделайте то же самое с последней строкой, то есть удалите (теперь одинокую )новую строку и все до последней ;и замените на ;.

  7. Готово.

Или вы можете просто использовать код awk.

8
27.01.2020, 21:12

Еще один сед с петлей:

sed ':A;s/\([^.]*\.[^.]*\)\.\(.*;[^;]*$\)/\1,\2/;tA' infile
-1
27.01.2020, 21:12

Вы можете подойти к этому с помощью редактора sedследующим образом:

$ sed -e '
    y/./\n/
    s/\n\(.*\)\n/.\1./
    y/\n/,/
' input.txt

Предпосылка состоит в том, что мы сначала превращаем все точки в символы новой строки, а символ гарантированно отсутствует в пространстве шаблонов. Затем мы меняем последнюю и первую новую строку обратно на точки. Все остальные символы новой строки преобразуются в запятые.

ХТН.

-1
27.01.2020, 21:12

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

sed 's/^\([^.]*\.[^.]*\)\.\([^.]*\)\.\([^.]*\)\.\([^.]*\)\./\1,\2,\3,\4,/'

Это разбивает каждую строку ввода следующим образом:

  • Группа захвата 1 :Начиная с начала строки, любое количество символов, кроме ., затем один.(первый в строке ), затем другая произвольно длинная последовательность символов, кроме .,
  • A.(второй в строке ),
  • Группа захвата 2 :Любое количество символов, кроме .,
  • A.(третий в строке ),
  • Группа захвата 3 :Любое количество символов, кроме .,
  • A.(четвертый в строке ),
  • Группа захвата 4 :Любое количество символов, кроме .,
  • A.(пятый в строке ),
  • Все, что следует за (, не соответствует регулярному выражению, но в строке может быть больше, чем выше, потому что регулярное выражение не заканчивается на $).

И заменяет его на

  • Группа захвата 1 :Все до второго .в строке (включая первый ),
  • А,(заменяет второй .),
  • Группа захвата 2 :Все между второй.и третьей,
  • A,(заменяет третий .),
  • Группа захвата 3 :Все между третьей.и четвертой,
  • A,(заменяет четвертый .),
  • Группа захвата 4 :Все между четвертой.и пятой,
  • А,(заменяет пятый .),
  • Все, что последует за пятым ..

Таким образом, он заменяет вторую, третью, четвертую и пятую точки запятыми.

  • Это не изменит строку, содержащую менее пяти точек.
  • Это оставит произвольное количество точек после пятой без изменений.
  • Это заменит вторую, третью, четвертую и пятую точки, даже если в строке (всего пять точек, т. е. нет шестой ).

Вот еще один подход, специально предназначенный для GNU sed:

sed 's/\./\n/6g; s/\./,/2g; s/\n/./g'
  • s/\./\n/6gзаменяет все точки, начиная с шестой, на новые строки.
  • s/\./,/2g  заменяет все точки, начиная со второй, запятыми. Но это действительно только со второго по пятый, поскольку первая команда удалила все точки после пятой (, если они есть ).
  • s/\n/./g заменяет все символы новой строки на точки. Конечно,единственные новые строки в строке те, которые изначально были точками, так что это просто меняет их обратно на то, что они были.

Итак, если в строке всего три точки, это изменит второй и третий (хотя четвертого и пятого не существует ).

Предупреждение:Поведение комбинации числа и gкак флаги в команде s не указаны в POSIX и может варьироваться в зависимости от реализации. Вот как это работает для GNU SED, как описано в руководстве GNU SED .

1
27.01.2020, 21:12

Теги

Похожие вопросы