Используйте sed для копирования на предыдущую строку

Я хочу преобразовать:

A,p
B,q
C,r
D,s

В:

A,p,q
B,q,r
C,r,s

Используя sed.

2
задан 9 January 2018 в 21:19

2 ответа

Я подозреваю, что sed не для этого (и другие могут знать, как сделать это намного лучше с sed), но здесь идет речь:

$ sed '2,$ s/.$/&,&/' file | sed -r ':a;N;s/\n(.)(,?.?)(,.)$/\3\n\1\2/;ta' | sed '$d'
A,p,q
B,q,r
C,r,s

Заметки

sed '2,$ s/.$/&,&/' означает дублирование последнего символа во всех строках, кроме первой, с добавлением запятой:

  • 2,$ со 2-й строки и далее
  • s/old/new/ заменяют old с new
  • .$ последним символом
  • & совпавшим шаблоном

sed -r ':a;N;s/\n(.)(,?.?)(,.)$/\3\n\1\2/;ta;' означает, что последний символ следует брать после каждой строки после первый и вставьте его в конец предыдущей строки:

  • -r используйте метку ERE
  • :a: выполните отсюда
  • ; разделяет команды
  • N считывает следующую строку в пространство шаблона, поэтому мы можем использовать \n для представления новых строк в шаблоне
  • (.) сохранить один символ для последующего использования
  • ? ноль или один из предшествующих символов
  • $ конец строки
  • \1 ссылка на сохраненный шаблон
  • ta, если последний Команда s выполнена успешно, перейдите к :a и выполните цикл снова
  • $d Удалите последнюю строку

Если в вашем файле нет только одного символа между запятые, вы не сможете использовать очень простое регулярное выражение выше. Вот версия, которая работает, если файл разделен запятой. Например, учитывая

January,apple
February,pear
March,kiwi
April,mango

Вы можете сделать это, что также работает, если там есть только один символ, конечно же скрипты

$ sed '2,$ s/[^,]*$/&,&/' file | sed -r ':a;N;s/\n([^,]*)(,?[^,]*)(,[^,]*)$/\3\n\1\2/;ta;' | sed '$d'
January,apple,pear
February,pear,kiwi
March,kiwi,mango

sed могут быть написано в несколько строк. Я не могу утверждать, что это значительно улучшает удобочитаемость;) но он может быть более переносимым, поскольку существуют ограничения на использование ; в не-GNU версиях sed:

sed '2,$ s/[^,]*$/&,&/' file |
sed -r '{:a
          N
          s/\n([^,]*)(,?[^,]*)(,[^,]*)$/\3\n\1\2/
          ta}' |
sed '$d'

[^,]* означает ноль или более символов, которые не являются запятыми.

3
ответ дан 9 January 2018 в 21:19

Вот способ сделать это за один вызов sed:

sed -nE '$!{:a;N;s/(.*)\n(.*)(,[^,]*$)/\1\3\n\2\3/;P;D;ba;}' file
A,p,q
B,q,r
C,r,s

Объяснение

Структура :a;N;...P;D;ba по существу поддерживает двухстрочный буфер, внутри которого мы можем разделите поля и скопируйте / переместите группы символов вокруг:

$!{                                   # For any line except the last
  :a                                  # Enter a loop:
  N                                   # Append the following line, after a newline  
  s/(.*)\n(.*)(,[^,]*)$/\1\3\n\2\3/   # Capture (1) up to the newline, 
                                      # (2) from the newline to the last comma, 
                                      # and (3) everything else into groups and 
                                      # copy group 3 before the newline
  P                                   # Print everything up to the newline
  D                                   # Delete everything up to the newline, 
                                      # ready for the next iteration
  ba
}

Обратите внимание, что использование расширенного регулярного выражения -E (или -r) не является обязательным - оно просто уменьшает количество экранирования, которое необходимо.

1
ответ дан 9 January 2018 в 21:19

Другие вопросы по тегам:

Похожие вопросы: