Выполните команду в одной строке несколько раз с помощью sed
мне нужно выделить каждое повторяющееся слово в тексте с *
символ.
Например
lol foo lol bar foo bar
должно быть
lol foo *lol* bar *foo* *bar*
я попробовал со следующей командой:
echo "lol foo lol bar foo bar" | sed -r -e 's/(b[a-zA-Z]+b)([^*]+)()/**/'
это дает мне:
lol foo *lol* bar foo bar
затем я добавил g
флаг:
lol foo *lol* bar foo *bar*
но foo
не выделены.
Я знаю, что это происходит потому, что sed
не оглядывается, если матч был найдено.
могу ли я справиться только с sed
?
2 ответов
Sed
- это не лучший инструмент для этой задачи. Он не смотрит вперед, не смотрит назад и не жадные кванторы, но попробуйте следующую команду:
sed -r -e ':a ; s/\b([a-zA-Z]+)\b(.*) ()( |$)/ ** / ; ta'
он использует условное ветвление для выполнения команды подстановки, пока не произойдет сбой. Кроме того, вы не можете проверить ([^*]+)
потому что для второго раунда он должен пересечь некоторые *
из первой замены, ваш вариант является жадным .*
. И, наконец, вы не можете соответствовать ()
только потому, что он будет соответствовать первому строка lol
снова и снова. Вам нужен какой-то контекст, например, окруженный пробелами или концом строки.
команду дает:
lol foo *lol* bar *foo* *bar*
обновление: улучшение предоставлен potong комментарии:
sed -r ':a;s/\b(([[:alpha:]]+)\s.*\s)\b/**/;ta' file
используя awk
awk '{for (i=1;i<=NF;i++) if (a[$i]++>=1) printf "*%s* ",$i; else printf "%s ",$i; print ""}' file
lol foo *lol* bar *foo* *bar*