Использование sed / awk для удаления строки из подразделов - PullRequest
0 голосов
/ 27 октября 2018

У меня есть файл, который выглядит следующим образом:

bar
barfo
barfoo
barfooo
barfoooo

sample
sampleText1
sampleText2
sampleText3

prefix
prefixFooBar
prefixBarFoo

Что я хочу сделать sed (или awk), это удалить строку, которая представляет раздел, из всего его содержимого, чтобы я могв итоге:

bar
fo
foo
fooo
foooo

sample
Text1
Text2
Text3

prefix
FooBar
BarFoo

Я пытался использовать

sed -e -i '/([[:alpha:]]+)/,/^$/ s/\1//g' file

Но это не сработало с "Invalid Backreference".

Ответы [ 8 ]

0 голосов
/ 28 октября 2018

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

sed 'G;s/^\(.\+\)\(.*\)\n\1$/\2/;t;s/\n.*//;h' file

Добавить предыдущий ключ (или ничего, если это первая строка) к текущей строке. Удалите ключ и предыдущий ключ, если они совпадают, напечатайте текущую строку и повторите. В противном случае ключ не совпадает, удалите старый добавленный ключ, сохраните новый ключ в поле удержания и распечатайте новый ключ.

0 голосов
/ 28 октября 2018

Еще в awk:

$ awk '{if(p&&match($0,"^" p))$0=substr($0,RLENGTH+1);else p=$0}1' file

Вывод:

bar
fo
foo
fooo
foooo

sample
Text1
Text2
Text3

prefix
FooBar
BarFoo
0 голосов
/ 28 октября 2018

Вот еще одно решение awk:

awk '{gsub(s,"")}1; s==""||!NF{s=$0}' file

Плюсы:

  • Матчи заменяются, где бы они ни были
  • Все спички заменены
  • Линия головы может оцениваться до 0 / false.
  • Строка заголовка может содержать пробел

Минусы:

  • Строка заголовка не должна содержать метасимволы регулярного выражения
0 голосов
/ 28 октября 2018
perl -ple'
   if (!length($_)) { $re = "" }
   elsif (!length($re)) { $re = $_ }
   else { s/^\Q$re// }
'

Примечания:

  • Используйте s/\Q$re//g для удаления в любом месте строки вместо простого удаления префикса.
  • Это работает даже со строкой заголовка, содержащей специальные символынапример \, . и *.
  • Это работает, даже если в строке несколько пустых строк.
  • См. Указание файла для обработки в Perl one-liner для полного использования.
  • Разрывы строк в коде необязательны (то есть могут быть удалены).
0 голосов
/ 28 октября 2018

Вот еще одно sed решение. Это работает, только если все строки в параграфе начинаются со строки темы.

sed -e '1{h;b};/^$/{n;h;b};H;g;s/\(.*\)\n\1//;p;g;s/\n.*//;h;d' file
  • 1 первая строка: h копирование в пробел, b печать и продолжение со следующей строкой
  • /^$/ пустые строки: n напечатать и прочитать следующую строку, h скопировать, чтобы сохранить пробел, b напечатать и продолжить
  • все (остальные) строки:
    • H добавить пробел с новой строки
    • g копировать удерживаемое пространство в пространство шаблона
    • s/\(.*\)\n\1// удалить первую строку и ее содержимое во второй строке из пространства шаблона
    • p пробел для печати
    • g скопировать удерживаемое пространство в пространство шаблона, чтобы удалить новое содержимое из H
    • /\n.*// удалить новое содержимое
    • h копировать обратно в пробел
    • d удалить пробел

sed бесполезен для этих вещей.

Вы получаете 'Недопустимая обратная ссылка', потому что в шаблоне поиска s.

нет группы.
0 голосов
/ 28 октября 2018

Решение sed, главным образом для иллюстрации того, что sed, вероятно, не лучший выбор для этого:

$sed -E '1{h;b};/^$/{n;h;b};G;s/^(.*)(.*)\n\1$/\2/' infile
bar
fo
foo
fooo
foooo

sample
Text1
Text2
Text3

prefix
FooBar
BarFoo

Вот как это работает:

1 {                   # on the first line
  h                   # copy pattern buffer to hold buffer
  b                   # skip to end of cycle
}
/^$/ {                # if line is empty
  n                   # get next line into pattern buffer
  h                   # copy pattern buffer to hold buffer
  b                   # skip to end of cycle
}
G                     # append hold buffer to pattern buffer
s/^(.*)(.*)\n\1$/\2/  # substitute

Сложная частьв замене.Перед заменой буфер шаблона содержит что-то вроде этого:

prefixFooBar\nprefix

Подстановка теперь соответствует двум группам захвата, на первую из которых ссылается то, что находится между \n и концом строки - префиксмы извлекаемся из буфера хранения.

Затем выполняется замена остальной части исходной строки с удаленным префиксом.

Примечания:

  • Это работает с GNUСЭД;более старая версия GNU sed может потребовать -r вместо -E
  • -E только для удобства;без него подстановка выглядела бы как

    s/^\(.*\)\(.*\)\n\1$/\2/
    

    , но все еще работала.

  • Для macOS sed она работает с буквальными переносами строк между командами:

    sed -E '1{
    h
    b
    }
    /^$/{
    n
    h
    b
    }
    G
    s/^(.*)(.*)\n\2$/\2/' infile
    
0 голосов
/ 27 октября 2018

еще awk

$ awk '{sub(pre,"")}1; !NF{pre=""} !pre{pre=$1}' file

bar
fo
foo
fooo
foooo

sample
Text1
Text2
Text3

prefix
FooBar
BarFoo
0 голосов
/ 27 октября 2018
$ awk '{$0=substr($0,idx)} !idx{idx=length($0)+1} !NF{idx=0} 1' file
bar
fo
foo
fooo
foooo

sample
Text1
Text2
Text3

prefix
FooBar
BarFoo
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...