Как работать только на части линии - PullRequest
6 голосов
/ 14 декабря 2010

Как заставить sed работать только на определенных участках линии?И, наоборот, как заставить sed не работать на определенных частях строки?

Примеры:

"A a A a ( A a ) A ( a A ) a"

Как, например, заменить все As с T s только между ( и ) для получения:

"A a A a ( T a ) A ( a T ) a"

И с учетом следующего примера ввода:

"F f F f ( F f ) F ( f F ) f"

Какнапример, заменить ли F s на X s, но not между ( и ), чтобы получить:

"X fX f (F f) X (f F) f "

Я искал в Google, но не нашел ничего пригодного для использования.Я думаю, что это общий вопрос о седе.Надеюсь, что проблема сводится к общим шаблонам sed,

  1. , имеющим FROM и TO, а затем работают только между ними (во всех случаях в данной строке)
  2. , имеющим FROM и TOработать где-то еще, чем между ними ...
  3. особый случай, когда FROM и TO одинаковы (между "и" или "FOO" и "FOO" и т. д.) для 1. и 2.

Он должен работать с любой операцией, не только с подстановкой, но и с печатью и т. Д., Например, печать всего между строками "FOO" и "BAR" в строке.

"1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q"

Результатбудет

" d e f  i j k "

Итак, общие примеры того, как это сделать, будут высоко оценены.Также кажется, что этот вопрос довольно распространенный, но в Google пока нет хороших инструкций.Я также думаю, что это будет довольно сложно ответить.Пожалуйста, также не давайте никаких подсказок о том, как это сделать, используя Perl, AWK или что-то еще, кроме sed.Этот вопрос действительно только для седов.

Ответы [ 2 ]

1 голос
/ 21 апреля 2014

Это может сработать для вас (GNU sed):

sed ':a;s/\(([^)]*\)A/\1T/;ta' file # for case 1

sed ':a;s/\(([^)]*\)F/\1\n/;ta;y/F\n/TF/' file  # for case 2

Для случая 1 используйте цикл для замены A внутренних скобок на T.

Для случая 2 используйте то же, что и выше, чтобы заменить внутренние скобки F на новые строки, затем переведите F и новые строки в X и F соответственно.

Случай 3 немного сложнее, но его можно выполнить двумя заменяющими командами:

sed -r 's/FOO|BAR/\n&/g;s/[^\n]*(\nBAR[^\n]*)*(\nFOO([^\n]*)\nBAR)?(\nFOO[^\n]*$)?/\3/g' file

Первый префикс каждой строки FOO и BAR с символами новой строки. Затем найдите все комбинации FOO и BAR и сохраняйте строки только между FOO и BAR. Новые строки позволяют использовать отрицательный класс для упрощения процедуры.

1 голос
/ 14 декабря 2010

Разделяй и властвуй.

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

$ echo "A a A a ( A a ) A ( a A ) a" |
    sed 's/([^)]*)/\n&/g; 
         :a; 
           s/\(\n([^)]*\)A\([^)]*)\)/\1T\2/;
         ta; 
         s/\n//g'
A a A a ( T a ) A ( a T ) a
$ echo "F f F f ( F f ) F ( f F ) f" | 
    sed 's/(/\n(/g; 
         s/)/)\n/g; 
         :a; 
           s/\([^(]*\)F\([^)]*\(\n\|$\)\)/\1X\2/g; 
         ta; 
         s/\n//g'
X f X f ( F f ) X ( f F ) f
$ echo "1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q" | 
    sed 's/^/BAR/;
         s/$/FOO/;
         s/FOO/&\n/g;
         s/BAR/\n&/g;
         s/BAR[^\n]*\n//g;
         s/[^\n]*FOO\n//g;
         s/\n//g'
 d e f  i j k
...