LINUX.ORG.RU

sed: изменить только внутри ЧАСТИ строки, которая соответствует паттерну

 ,


0

3

Всем привет

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

Например, есть строка
abc_1.2.3.4_cde ТАБ 1.2.3.4

Хочу из нее сделать
abc_1.2.3.4_cde ТАБ 1|2|3|4

Вот это не работает, так как меняет в СТРОКЕ, которая соответствует паттерну.

$ echo -e "abc_1.2.3.4_cde\t1.2.3.4" | sed '/\t[0-9.]\+/ { s/\./|/g }'

abc_1|2|3|4_cde 1|2|3|4

А как сделать чтобы менялось только в той части, что после табуляции?

★★★★★

Последнее исправление: Kroz (всего исправлений: 1)

Ответ на: комментарий от Deleted

4 - это 4-ое совпадение?
Не подходит, ибо цифр и точек может быть произвольное количество.

Kroz ★★★★★
() автор топика

А как сделать чтобы менялось только в той части, что после табуляции?

Можно так, но надо ли ону кому такое страшное?

$ echo -e "abc_1.2.3.4_cde\t1.2.3.4" |
sed '/\t[0-9.]\+/ { h; x; s/\t[0-9.]\+/\n/; x; s/.*\(\t[0-9.]\+\).*/\1/; y/./|/; H; x; s/\([^\n]*\)\n\([^\n]*\)\n\(.*\)/\1\3\2/ }'
abc_1.2.3.4_cde 1|2|3|4
Тут (возможно, можно сделать проще):

  • исходная строка кладётся в hold как <до>\n<после>
  • в pattern оставляем только <середину>
  • выполняем замену
  • дописываем результат в hold и получаем <до>\n<после>\n<середина после замены>
  • меняем последние две части местами, удаляя переводы строк

Сделал из интереса, сам бы не стал использовать.

xaizek ★★★★★
()

Два варинта, первый в цикле заменяем точки после табуляции:

echo -e "abc_1.2.3.4_cde\t1.2.3.4" | sed ':a;s/\(\t[^.]*\)./\1|/g; ta'
второй режем строку по табуляции, начало в hold, хвост в pattern буферах, обрабатываем хвост и склеиваем:
echo -e "abc_1.2.3.4_cde\t1.2.3.4" | sed 'h;s/\t.*//;x;s/[^\t]*//;s/\./|/g;H;x;s/\n//'

mky ★★★★★
()

несколько sed

echo -e "abc_1.2.3.4_cde\t1.2.3.4" | sed 's/\t[0-9\.]/\n/' | sed 'n;s/\./|/g' | sed 'N;s/\n/\t/'

anonymous
()
$ echo -e 'abc_1.2.33.444_def\t1.2.33.444' | perl -pne 's/[.](?=([.]?\d+)+$)/|/g'
abc_1.2.33.444_def	1|2|33|444
ashot ★★★★
()
Ответ на: комментарий от Deleted

a sed принципиален?

Принципе нет, но тогда мне нужно будет учить awk; например, как делать подстановки вида sed'овского \1 с нахрапа не нашел.

Хотя, должен признаться, что вариант с awk более гибкий и наглядный.

Kroz ★★★★★
() автор топика
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от mky

Спасибо. Сделал первым способом.
Реальная задача состояла в замене однозначных чисел двузначными. Вот что вышло:

$ echo -e "abc_1.2.3.4_cde\t1.2.3.4" | sed ':a;s/\t\(\([0-9]\{2,\}\.\)*\)\([0-9]\)\(\.\|\t\|$\)/\t\10\3\4/g;ta'
abc_1.2.3.4_cde 01.02.03.04

Kroz ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.