Intereting Posts
Перегородка не установлена ​​из fstab Сценарий, чтобы сравнить дату работы с сегодняшней датой и выводить только сегодняшние неудачи Попытка установить 32-битный java-плагин на Centos 6.5 64-bit mozilla firefox syslog: Служба отмечена как исполняемый файл. Удалите исполняемые биты разрешения. В любом случае как сделать системное обслуживание из .jar-файла? (Linux) Передача glob-выражений в функции / скрипты Как мы можем сохранить вывод команды в виде массива в сценарии оболочки Unix? пользовательский sysconfdir для coreutils Маленький скрипт для обновления цветов GNOME Terminal 3.14.2 Получить путь к текущему отмеченному файлу Потерянные заголовки окон и все после выбора темы плохого окна в Linux Mint Добавить и выписать файл с переменными именами из списка переменных Звук RME Multiface (HDSP) на Debian / Jessie (Systemd / PulseAudio) Как безопасно деактивировать разрешения для поддерева Команды X не начинаются с моей работы

Confused by sed output при использовании N. Кто-нибудь может объяснить эти результаты?

Я изучаю sed. Кажется, все идет хорошо, пока я не наткнулся на N (многострочный следующий). Я создал этот файл (guide.txt) для целей практики / понимания / контекста. Вот содержимое указанного файла …

This guide is meant to walk you through a day as a Network Administrator. By the end, hopefully you will be better equipped to perform your duties as a Network Administrator and maybe even enjoy being a Network Administrator that much more. Network Administrator Network Administrator I'm a Network Administrator 

Поэтому моя цель – заменить ВСЕ экземпляры «Network Administrator» на «System User». Поскольку первый экземпляр «Network Administrator» разделяется символом новой строки (\ n), мне нужен следующий оператор (N) для нескольких строк, чтобы добавить строку, начинающуюся с «Administrator», с предыдущей строкой, заканчивающейся «Network \ n», , Нет проблем. Но я также хочу поймать всех других однострочных экземпляров «Сетевой администратор».

Из моих исследований я узнал, что мне понадобятся две команды подстановки; один для строки, разделенной новой строкой, и другой для остальных. Кроме того, происходит некоторое джайв из-за последней строки, содержащей совпадение подстановки и многострочный следующий. Поэтому я создаю это …

 $ sed ' > s/Network Administrator/System User/ > N > s/Network\nAdministrator/System\nUser/ > ' guide.txt 

Это возвращает эти результаты …

 This guide is meant to walk you through a day as a System User. By the end, hopefully you will be better equipped to perform your duties as a System User and maybe even enjoy being a Network Administrator that much more. System User Network Administrator I'm a System User 

Я думал, что однострочная подстановка поймает все «обычные» экземпляры «Network Administrator» и заменит их «System User», в то время как многострочный оператор будет работать с маской на экземпляре, отделенном новой строкой, но поскольку вы может видеть, что он вернулся, что я считаю неожиданными результатами.

После некоторого ворчания я приземлился на этом …

 $ sed ' > s/Network Administrator/System User/ > N > s/Network\nAdministrator/System\nUser/ > s/Network Administrator/System User/ > ' guide.txt 

И вуаля, я получаю желаемый результат …

 This guide is meant to walk you through a day as a System User. By the end, hopefully you will be better equipped to perform your duties as a System User and maybe even enjoy being a System User that much more. System User System User I'm a System User 

Почему эта работа и исходный сценарий sed нет? Я действительно хочу это понять.

Заранее благодарю за любую помощь.

Когда вы изучаете sed , я потрачу время, чтобы добавить к ответу @ John1024:

1) Обратите внимание, что вы используете \n в строке замены. Это работает в GNU sed , но не является частью POSIX, поэтому он будет вставлять обратную косую черту и n во многих других sed s (использование \n в шаблоне переносится, кстати).

Вместо этого я предлагаю сделать s/Network\([[:space:]]\)Administrator/System\1Us‌​er/g : [[:space:]] будет соответствовать новой строке или пробелу, так что вы не нужны две команды s , но объедините их в один. Окружая его \(...\) вы можете ссылаться на него в замене: \1 заменит все, что было сопоставлено в первой паре \(\) .

2) Чтобы правильно сопоставить шаблоны над двумя строками, вы должны знать шаблон N;P;D :

  sed '$!N;s/Network\([[:space:]]\)Administrator/System\1User/g;P;D' 

N всегда добавляет следующую строку (за исключением последней строки, поэтому она «адресуется» с помощью $! (= Если не последней строки, вы всегда должны считать, чтобы превалировать N с помощью $! Чтобы избежать случайного окончания скрипта). после замены P печатает только первую строку в пространстве шаблонов, а D удаляет эту строку и запускает следующий цикл с остатками пространства шаблонов (без прочтения следующей строки). Вероятно, это то, что вы изначально планировали.

Помните этот шаблон, вам он часто понадобится.

3) Еще один полезный шаблон для многострочного редактирования, особенно когда задействовано более двух строк: Удерживайте пространство, как я предложил Джону:

 sed 'H;1h;$!d;g;s/Network\([[:space:]]\)Administrator/System\1Us‌​er/g' 

Я повторяю это, чтобы объяснить это: H присоединяет каждую строку к пространству удержания. Поскольку это приведет к добавлению новой строки перед первой строкой, первая строка должна быть перемещена, а не добавлена ​​с 1h . Следующие $!d означают «для всех строк, кроме последнего, удалите пространство шаблонов и начните заново». Таким образом, остальная часть скрипта выполняется только для последней строки. На этом этапе весь файл собирается в пространстве удержания (поэтому не используйте его для очень больших файлов!), И g перемещает его в пространство шаблонов, поэтому вы можете делать все замены сразу, как вы можете, с помощью -z для GNU sed .

Это еще одна полезная модель, которую я предлагаю иметь в виду.

Во-первых, обратите внимание, что ваше решение не работает. Рассмотрим этот тестовый файл:

 $ cat test1 Network Administrator Network Administrator 

Затем запустите команду:

 $ sed ' s/Network Administrator/System User/ N s/Network\nAdministrator/System\nUser/ s/Network Administrator/System User/ ' test1 System User Network Administrator 

Проблема в том, что код не заменяет последнего Network\nAdministrator .

Это решение действительно работает:

 $ sed ':a; /Network$/{$!{N;ba}}; s/Network\nAdministrator/System\nUser/g; s/Network Administrator/System User/g' test1 System User System User 

Мы также можем применить это к вашему guide.txt :

 $ sed ':a; /Network$/{$!{N;ba}}; s/Network\nAdministrator/System\nUser/g; s/Network Administrator/System User/g' guide.txt This guide is meant to walk you through a day as a System User. By the end, hopefully you will be better equipped to perform your duties as a System User and maybe even enjoy being a System User that much more. System User System User I'm a System User 

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

Замечание по совместимости: все вышеперечисленное использует \n в тексте замены. Для этого требуется GNU sed. Он не будет работать с BSD / OSX sed.

[Кончик шляпы Филиппу .]

Многострочная версия

Если это помогает прояснить, вот та же команда, разделенная на несколько строк:

 $ sed ':a /Network$/{ $!{ N ba } } s/Network\nAdministrator/System\nUser/g s/Network Administrator/System User/g ' filename 

Как это работает

  1. :a

    Это создает метку a .

  2. /Network$/{ $!{N;ba} }

    Если эта строка заканчивается Network , то если это не последняя строка ( $! ), Прочитайте и добавьте следующую строку ( N ) и ответьте назад на метку a ( ba ).

  3. s/Network\nAdministrator/System\nUser/g

    Сделайте замену промежуточной новой строкой.

  4. s/Network Administrator/System User/g

    Сделайте замену промежуточной заготовкой.

Упрощенное решение (только для GNU)

С GNU sed ( не BSD / OSX) нам нужна только одна команда подстановки:

 $ sed -zE 's/Network([[:space:]]+)Administrator/System\1User/g' test1 System User System User 

И в файле guide.txt :

 $ sed -zE 's/Network([[:space:]]+)Administrator/System\1User/g' guide.txt This guide is meant to walk you through a day as a System User. By the end, hopefully you will be better equipped to perform your duties as a System User and maybe even enjoy being a System User that much more. System User System User I'm a System User 

В этом случае -z сообщает sed прочитать до первого символа NUL. Поскольку текстовые файлы никогда не имеют нулевого символа, это приводит к одновременному чтению всего файла. Затем мы можем сделать замену, не беспокоясь о пропуске строки.

Этот метод не очень хорош, если файл огромен (обычно это означает гигабайт). Если он такой большой, то сразу все его считывание может привести к повреждению системной ОЗУ.

Решение, которое работает как с GNU, так и с BSD

Как было предложено Phillipos , следующее портативное решение:

 sed 'H;1h;$!d;x;s/Network\([[:space:]]\)Administrator/System\1Us‌​er/g'