Переупорядочить несколько линейных блоков с помощью Sed

Я пытаюсь изменить порядок сгенерированного вывода следующим образом; учитывая фрагмент tex следующим образом, я хочу переместить /^Constant/ down ниже /Dummies/ , с линией до и после /^Constant/ . Кроме того, мне бы хотелось получить стабильный результат, который не вносит изменений, если Constant уже находится ниже последней строки Dummies (он работает как часть скрипта, чтобы исправить мои результаты исследований, и до сих пор этот сценарий стабилен).

Это вход фрагмента tex:

 [1em] Application Grade& & & -0.0857\sym{***}& -0.00412\sym{***}\\ & & & (0.0149) &(0.00107) \\ [1em] Constant & -3.701\sym{***}& -0.311\sym{***}& 0 & 0 \\ & (1.130) & (0.0853) & (.) & (.) \\ [1em] Major Dummies & No & No & Yes & Yes \\ [1em] Semester Dummies & No & No & Yes & Yes \\ \hline 

Это желаемый результат, который остается стабильным (возвращает то же самое), если он задан как вход:

 [1em] Application Grade& & & -0.0857\sym{***}& -0.00412\sym{***}\\ & & & (0.0149) &(0.00107) \\ [1em] Major Dummies & No & No & Yes & Yes \\ [1em] Semester Dummies & No & No & Yes & Yes \\ [1em] Constant & -3.701\sym{***}& -0.311\sym{***}& 0 & 0 \\ & (1.130) & (0.0853) & (.) & (.) \\ \hline 

Следующий код будет делать это, но он нестабилен. В основном он совпадает с Constant , капли и повторные вставки [1em] (что он должен делать на отдельный вызов, так как i\ влияет на результат, а не на пространство рисунка) и пасты ниже цели. Он нестабилен, потому что он добавит фиктивные [1em] s после Semester Dummies . Честно говоря, его немного уродливое (требуя отдельных вызовов sed ).

 sed -E -i'' -e'/^Constant/ {N;h;N;d;}; /^Semester Dummies/ {G;};' fragment.tex sed -E -i'' -e '/^Semester Dummies/ {a\ \[1em\] };' fragment.tex 

Я считаю, что один лайнер сделает это, сопоставляя многострочный шаблон / ^\[ /^\[1em\]\nConstant.*/ (после вызова N;N; ), помещая его в h старый буфер, а затем вставляя его ( G; ) после /Semester Dummies/ . Но после многих часов, man-страниц, веб-поиска и обновления для gnused для хорошей меры, я не могу заставить такой скрипт работать. Это выражает основную идею, но недействительно (s не может условно h как я здесь):

 sed -E -i'' -e'/\[1em\]/ {N;N;s/^\[1em\]\nConstant.*//h;}; /Semester Dummies/ {G;}' fragment.tex 

Я пробовал много вариантов, полагаясь на N;P;D;h;G; с различной адресацией, но я все еще не понимаю порядок выполнения для многократно адресуемых команд, когда вы возитесь с пространством шаблонов (вызывая N; ). N и P работают красиво, но, насколько я могу судить, D совершенно бесполезен.

Да, я знаю, что проще с awk и perl ; на самом деле, мне было бы интересно увидеть все три решения для сравнения – но здесь я специально спрашиваю, как это сделать в sed .

  • Согласование шаблонов по нескольким строкам
  • извлекать часть строки, используя sed
  • как поменять текст внутри файлов
  • Сортировка нескольких файлов csv на основе двух столбцов в каталоге
  • Транспонирование файла и замена отсутствующих значений
  • Как правильно добавить концы строк с помощью sed?
  • Удалить строки из файла с помощью awk или sed на основе переменной из предыдущей команды
  • Как избежать повторения команд sed при добавлении сайтов в лак?
  • 2 Solutions collect form web for “Переупорядочить несколько линейных блоков с помощью Sed”

    Вот уродливый кусок awk, который играет трюки с разделителем записей

     awk -v RS='\\[1em\\]\n|\\\\hline' ' !/[^[:space:]]/ {next} /^Constant/ {c=$0; next} {printf "[1em]\n%s", $0} END {printf "[1em]\n%s\\hline\n", c} ' 

    Поскольку текст начинается и заканчивается «разделителем записи», есть некоторые ложные записи с пустыми-иш, следовательно, первое правило

    Вот один из способов сделать это с помощью sed с помощью буфера удержания:

     sed '/\[1em\]/{N;/Constant/{N;x;/^$/d;x};/Semester/{x;/^$/!{H;x};//g}}' file 

    В каждой строке, соответствующей [1em] она читается в строке N ext, а затем

    1. Если пространство шаблонов соответствует Constant она читает в другой строке, e x изменяет буферы, и если пространство шаблонов – это просто пустая строка (это означает, что буфер удержания был пуст перед обменом), он будет изменен. Если пространство шаблонов не является пустой линией (что означает, что в пространстве удержания было что- то из-за 2 ), e x снова меняет буферы, возвращая строки в пространстве шаблонов.
    2. Если пространство шаблонов совпадает с Semester e x изменяет буферы, тогда, если пространство [1em]\nConstant.* не пусто, это означает, что строки [1em]\nConstant.* Были в буфере удержания, поэтому он добавляет их в [1em]\nSemester.* (которые теперь находятся в буфере удержания), а затем e x снова изменяет буферы. Если пространство шаблонов пуст, это означает, что строки [1em]\nConstant.* Находятся после строки Semester поэтому он просто копирует пространство удержания над пространством шаблона. Таким образом восстанавливаются строки [1em]\nSemester.* , Но теперь есть что-то в буфере удержания, когда оно достигает 1 .

    Таким образом, строки [1em]\nConstant.* только в том случае, если они есть до [1em]\nSemester.* , В противном случае ничего не происходит.

     sed '/\[1em\]/{ # if line matches [1em] N # read in the next line /Constant/{ # if pattern space matches Constant N # read in another line x # exchange buffers /^$/d # if pattern space is now empty, delete it x # otherwise, exchange again } /Semester/{ # if pattern space matches Semester x # exchange buffers /^$/!{ # if pattern space is not empty H # append it to hold space x # then exchange buffers } //g # if pattern space is currently empty } # copy the hold space over the pattern space }' infile # so now the hold space is no longer empty 

    Это проще с ed . Просто выберите диапазон строк и переместите его после строки, соответствующей Semester :

     ed -s infile <<<$'/Constant/-1,/Constant/+1m/Semester/\n,p\nq' 

    замените ,p на w чтобы записать изменения в файл:

     ed -s infile <<IN /Constant/-1,/Constant/+1m/Semester/ w q IN 
    Interesting Posts

    извлечение строк текста из длинного файла

    почему права собственности на файловую систему не влияют после монтирования?

    проблема с if else в awk

    Как узнать глубину пикселя моей графической карты?

    USB-клавиатура работает с перебоями в GRUB 2 при перезагрузках – как заставить ее работать последовательно?

    Как сделать OR grep (с разными настройками GREP_COLOR)

    Как скопировать каждый 4-й файл в папку

    «Система сейчас идет на перезагрузку»

    Переключиться на родительскую оболочку без выхода из системы

    Утилита командной строки для визуализации того, как быстро растет файл?

    Ошибка загрузки Windows 7 после установки CentOS 7, как я могу ее вернуть?

    Как передать аргументы для команды через ярлык Desktop без открытия терминала?

    Не удается смонтировать флэш-накопитель USB 3.0

    Как добавить «открыть папку в качестве пользователя» в контекстном меню «Элементарный файловый менеджер ОС»?

    extract Встроенные initramfs

    Linux и Unix - лучшая ОС в мире.