Как заменить сразу несколько шаблонов на sed?
Предположим, у меня есть строка 'abbc' и я хочу заменить:
- ab - > bc
- bc - > ab
Если я попробую два заменяет результат не то, что я хочу:
echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab
Итак, какую команду sed я могу использовать для замены, как показано ниже?
echo abbc | sed SED_COMMAND
bcab
EDIT:
На самом деле текст может иметь более 2 шаблонов, и я не знаю, сколько замен мне понадобится. Поскольку был ответ, говорящий, что sed - это редактор потока и его замены жадно я думаю, что мне нужно будет использовать какой-то язык сценариев для этого.
7 ответов:
может, что-то вроде этого:
sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'заменить
~символ, который вы знаете, не будет в строке.
вот вариация на тему ответ УГА это работает для нескольких пар поиска и замены без необходимости проверять, как значения могут быть повторно использованы:
sed -i ' s/\bAB\b/________BC________/g s/\bBC\b/________CD________/g s/________//g ' path_to_your_files/*.txtвот пример:
перед:
some text AB some more text "BC" and more text.после:
some text BC some more text "CD" and more text.отметим, что
\bобозначает границы слов, что и мешает________от вмешательства в поиск (я использую GNU sed 4.2.2 на Ubuntu). Если вы не используете границу слова ищите, тогда эта техника может не сработать.также обратите внимание, что это дает те же результаты, что и удаление
s/________//gи добавить&& sed -i 's/________//g' path_to_your_files/*.txtдо конца команды, но не требует указания пути дважды.общее изменение на этом можно было бы использовать
\x0или_\x0_на месте________если вы знаете, что никакие нули не появляются в ваших файлах,как предложил Джилл.
sed- Это редактор потока. Он ищет и заменяет жадно. Единственный способ сделать то, что вы просили, - это использовать промежуточный шаблон подстановки и изменить его в конце.
echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'
Это может сработать для вас (GNU sed):
sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:()([^:]*))/\n/;ta;s/\n(.)/\n/;ta' fileЭто использует таблицу поиска, которая подготовлена и хранится в пространстве хранения (HS), а затем добавляется к каждой строке. Уникальный маркер (в данном случае
\n) добавляется к началу строки и используется в качестве метода для bump-вдоль поиска по всей длине строки. Как только маркер достигает конца строки, процесс завершается и распечатывается таблица поиска и маркеры отбрасываются.N. B. The таблица поиска подготавливается в самом начале и второй уникальный маркер (в данном случае
:) выбрано так, чтобы не конфликтовать со строками подстановки.С некоторыми комментариями:
sed -r ' # initialize hold with :abbc:bcab 1 { x s/^/:abbc:bcab/ x } G # append hold to patt (after a \n) s/^/\n/ # prepend a \n :a /\n\n/ { P # print patt up to first \n d # delete patt & start next cycle } s/\n(ab|bc)(.*\n.*:()([^:]*))/\n/ ta # goto a if sub occurred s/\n(.)/\n/ # move one char past the first \n ta # goto a if sub occurred 'таблица работает следующим образом:
** ** replacement :abbc:bcab ** ** pattern
Я всегда использую несколько операторов с "- e"
$ sed -e 's:AND:\n&:g' -e 's:GROUP BY:\n&:g' -e 's:UNION:\n&:g' -e 's:FROM:\n&:g' file > readable.sqlэто добавит '\n 'перед всеми AND, GROUP BY, UNION и FROM, тогда как' & 'означает согласованную строку и' \n& ' означает, что вы хотите заменить согласованную строку на '\n' перед 'согласованной'
Tcl имеет builtin для этого
$ tclsh % string map {ab bc bc ab} abbc bcabэто работает, проходя строку символа в то время, делая сравнение строк, начиная с текущей позиции.
в perl:
perl -E ' sub string_map { my ($str, %map) = @_; my $i = 0; while ($i < length $str) { KEYS: for my $key (keys %map) { if (substr($str, $i, length $key) eq $key) { substr($str, $i, length $key) = $map{$key}; $i += length($map{$key}) - 1; last KEYS; } } $i++; } return $str; } say string_map("abbc", "ab"=>"bc", "bc"=>"ab"); 'bcab
здесь
awkна основе oogassedecho 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1' bcab
Comments