2010-12-02 3 views
10

Как я могу использовать команды для обмена двумя строками, например, команды H, h, x, g, G.Обмен двумя строками

Например, в файле

START 
this is a dog 
this is a cat 
this is something else 
END 

сказать, что я хочу поменять «это собака» с «это что-то другое».

Это то, что я до сих пор:

/this is a dog/{ 
h # put to hold space 
} 
/this is something else/{ 
# now i am stuck on what to do. 
} 

ответ

19

Если вы знаете, рисунок на каждом из двух линий, которые вы хотите поменять, но не полное содержимое строк, вы можете сделать что-то вроде этого:

sed -n '      # turn off default printing 
    /dog/{     # if the line matches "dog" 
      h     # put it in hold space 
      :a    # label "a" - the top of a loop 
      n     # fetch the next line 
      /something/{  # if it matches "something" 
         p  # print it 
         x  # swap hold and pattern space 
         bb # branch out of the loop to label "b" 
      }     # done with "something" 
          # if we're here, the line doesn't match "something" 
      H     # append pattern space to hold space 
      x     # swap hold and pattern space 
      s/\([^\n]*\)\n\([^\n]*\)$/\2\n\1/ # see below 
      x     # swap hold and pattern space 
      ba    # branch to the top of the loop to label "a" 
    }      # done with "dog" 
    :b      # label "b" - outside the loop 
          # print lines that don't match and are outside the pair 
    p      # also prints what had been accumulating in hold space 
    ' inputfile 

картины замещения держит «собаку» в конце накопленных линий. Он продолжает заменять последние две строки, которые мы держим в удержании, чтобы «собака» «пузырилась» на дно.

Например, давайте поместим еще одну строку после строки «cat», чтобы процесс был немного яснее. Мы будем игнорировать строки перед «собакой» и после «что-то». И я по-прежнему относятся к линиям, используя мои прозвища

this is a dog 
this is a cat 
there's a bear here, too 
this is something else 

«Собака» читается, то «кошка» забирается. Некоторые добавления и замены выполняются. Теперь картина пространство выглядит следующим образом (\N представляет собой символ новой строки, я использую верхний регистр «N», так что выделяется, то ^ является началом шаблона и $ конца):

^this is a dog\Nthis is a cat$ 

Команда подстановки ищет любое количество символов, которые не являются символами новой строки (и захватывает их), за которыми следует новая строка, за которой следует любое количество символов, которые не являются символами новой строки (и захватывают их), которые находятся в конце строки ($), и заменяет все это с двумя захваченными строками в обратном порядке, разделенными новой строкой. Теперь пространство в пространстве выглядит так:

^this is a cat\Nthis is a dog$ 

Теперь мы поменяем местами и прочитаем новую строку. Это не «что-то» так мы делаем некоторые добавление и замена и теперь мы имеем:

^this is a cat\Nthis is a dog\Nthere's a bear here, too$ 

Мы делаем замену снова и получить:

^this is a cat\Nthere's a bear here, too\Nthis is a dog$ 

Почему мы не получили «медведь/собака/кот "? Поскольку шаблон регулярного выражения, состоящий из двух строк (каждый из которых, как обычно, состоит из не-новых строк, за которым следует новая строка), привязан в конце строки, используя $, поэтому мы игнорируем все, что приходит перед ним.Обратите внимание, что последняя строка новой строки подразумевается и фактически не существует в шаблоне или пространстве удержания. Вот почему я не показываю его здесь.

Теперь мы читаем «что-то» и печатаем его. Мы поменяемся местами. Привет! есть вещи, которые мы «пузырялись». Филиал и печать. Так как «собака» находится в нижней части строк (которые были накоплены в удержании), и мы напечатали «что-то» прямо перед этой связкой, эффект заключается в том, что мы поменяли местами две линии.

Этот скрипт будет работать независимо от того, сколько строк отображается до, между двумя или после двух строк, подлежащих обмену. Фактически, если имеется несколько пар совпадающих строк, члены каждой пары будут обмениваться по всему файлу.

Как вы можете видеть, я использую только одно слово в интересующих вас строках, но любое подходящее регулярное выражение будет делать.

+1

+1 для замечательных комментариев. – galaxywatcher 2012-01-30 13:57:30

2
/this is a dog/{ 
    h # put line in hold space 
    s//this is something else/ # replace with 'this is something else' 
    b # branch to end of the script 
} 
/this is something else/x # swap hold space with pattern space 

С sed это потоковый редактор вы действительно не может заменить текущую строку с содержимым будущих линий. Однако вы можете сделать обратное и заменить будущие строки на линию, которую вы уже видели, и это то, что делает мой сценарий.

Возможно, другим способом было бы использовать команду N, чтобы добавить каждую строку в пространство шаблонов, а затем выполнить две команды s, чтобы поменять местами две литералы.

Смежные вопросы