Попробуйте -m
флаг, возможно, объединенный с -T
и/или -x
(или -x standalone
).
Если ваш ввод не содержит <
, >
или +
символов, вы можете сделать:
sed '
s/[[:alnum:]]\{1,\}/<&>/g;:1
s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
s/[<>]//g'
Если это возможно, вы всегда можете избежать их:
sed '
s/:/::/g;s/</:{/g;s/>/:}/g
s/[[:alnum:]]\{1,\}/<&>/g;:1
s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
s/[<>]//g
s/:}/>/g;s/:{/</g;s/::/:/g'
Те, кто предполагают, что вы хотите сделать это независимо на каждой строке. Если Вы хотите сделать это по всему файлу, то сначала нужно загрузить весь файл в память (обратите внимание, что некоторые реализации sed
имеют там ограничения по размеру):
sed '
:2
$!{N;b2
}
s/:/::/g;s/</:{/g;s/>/:}/g
s/[[:alnum:]]\{1,\}/<&>/g;:1
s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
s/[<>]//g
s/:}/>/g;s/:{/</g;s/::/:/g'
Это будет довольно неэффективно и было бы намного проще с perl
:
perl -pe 's/\w+/$seen{$&}++ ? "+$&+" : $&/ge'
На основе строк:
perl -pe 'my %seen;s/\w+/$seen{$&}++ ? "+$&+" : $&/ge'
Вот еще один подход: это использует несколько SED
:
an='[:alnum:]' esc=$(printf '\033\[')
sed "/[${an}]/!d;=;a\ }
s/.*/ & /;s/[^${an}]\{1,\}/ /g
s| \([${an}"']\{1,\}\) | \
s/\\([^+'"${an}"']\\)\\(\1\\)\\([^+'"${an}"']\\)/\\1+\\2+\\3/2|g
' <text |
sed '/^ /!N;s/\n */{/' |
sed -e 's/.*/ & /;s/+/ & /g' \
-f - \
-e "s/ //;s/ $//
s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
s/ + /+/g" text
в основном, первые два SED
, чтобы написать скрипт на третий. Первый SED
очищает все, кроме буквенно-цифровых символов с каждой строки - и пропускает полностью любую строку без одного. Для всех групп персонажей, которые остаются, он пишет заявление подстановки, что третьи в конечном итоге (почти мгновенно) прочитано и интерпретировать как его скрипт.
Второе SED
необходимо, потому что первое пишет свой скрипт по линии - и каждая строка может иметь несколько ///
утверждений. Первые печатает свой номер строки для каждой строки, который содержит буквенно-цифровую, но это необходимо подключить в контексте функции для третьего SED
- и поэтому второй делает это.
Вот образец того, как выглядит сценарий:
...
43{
s/\([^+[:alnum:]]\)\(n\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(N\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(G\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
44{
s/\([^+[:alnum:]]\)\(b\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(block\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
45{
s/\([^+[:alnum:]]\)\(END\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(SEDSCRIPT\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
Существует трейлинг 2
для каждого ///
- это потому, что каждая замена направлена на Второе возникновение каждого рисунка - если второе происшествие не существует, ничего не замещена. Вышеуказанное является результатом пробега его на другом из моих SED
скриптов - кажется довольно невосприимчивым к специальным персонажам или подобным.
Как я пишу, я обнаружил, что было легче сказать, что происходит, если я окрашиваю свой выбор - это то, что ...
s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
... эта линия делает. Вы можете комментировать или удалить его, вы когда-либо использовали это вообще и не хотите или не нуждаетесь в этом.
Вот сценарий, который он пишет для вашего примера данных:
1{
s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(xyz\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(aa\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
Вот что он печатает:
qq ab xyz +ab+ +qq+ aa +ab+
и из некоторых из моих SED
скрипт от ранее:
s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${+esc+}0m/g
s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${+esc+}0m/g
s/.${bs}//g
s/\(\(${esc}\)0m\2[^m]*+m+[_ ]\{,+2+\}\)\{+2+\}/_/g
n; /./!N;G