Как искать слово, сохраненное в пространстве удержания с помощью sed?

Это sed специфический вопрос; Я хорошо знаю, что это можно сделать с помощью других инструментов, но я работаю над расширением моих знаний о sed .

Как я могу использовать sed для глобального цитирования (на самом деле backtick) слово, которое не указано в скрипте? Слово удерживается в пространстве удержания.

Я хочу что-то вроде:

 s/word/`&`/g 

Но трюк заключается в том, что word будет содержаться не в сценарии sed, а в пространстве удержания. Таким образом, это выглядит примерно так:

 H g s/^\(.*\)\n\(.*\)\1\(.*\)$/\2`\1`\3/ 

в котором будет указано одно из слов, удерживаемых в пространстве удержания. Я хочу процитировать все из них, но я не могу просто добавить флаг g из-за того, как это использует обратные ссылки, а не статическое regex.

 H g s/^\(.*\)\n\(.*\)\1\(.*\)\1\(.*\)$/\2`\1`\3`\1`\4/ 

Это обрабатывает два вхождения слова, но терпит неудачу на одном и игнорирует более одного.

Я думал, что могу использовать что-то чистое и простое:

 s//`&`/g 

Но это повторное использование последнего используемого регулярного выражения , а не то, что оно соответствует. (Это имеет смысл.)

Есть ли способ в sed делать то, что я пытаюсь сделать? (На самом деле мне было бы интересно увидеть, как легко это будет в perl , но я все равно хотел бы посмотреть, как это сделать в sed .)


ОБНОВИТЬ

Не то, чтобы это было необходимо для этого вопроса, но я подумал, что я расскажу немного больше о том, что именно я делал, когда я придумал этот вопрос:

У меня был большой текстовый файл документации, некоторые части которого нужно было сжать и суммировать в таблицу asciidoc . Это было довольно легко из-за Description: и Prototype: lines и т. Д., Поэтому я на самом деле написал быстрый скрипт sed чтобы сделать все синтаксический анализ для меня. Он работал красиво, но единственное, чего не хватало, это то, что я хотел отменить слова в строке Description которые соответствовали аргументам, перечисленным в строке Prototype . Линии прототипов выглядели примерно так:

 Prototype: some_words_here(and, arg, list,here) 

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

Однако, учитывая, что иногда arg соответствовал бы части слова, которую я не хотел получать, и иногда имя arg было общим словом (например, from ), которое я только хотел получить назад, когда оно было использовано в контекст объяснения использования функции, автоматическое решение на самом деле не было хорошей подгонкой, и вместо этого я использовал vim для выполнения задания полу-вручную с помощью некоторых сложных макросов. 🙂

2 Solutions collect form web for “Как искать слово, сохраненное в пространстве удержания с помощью sed?”

Это было тяжело. Предполагая, что у вас есть такой file :

 $ cat file word line with a word and words and wording wordy words. 

Где:

  • Строка 1: шаблон поиска, который должен удерживаться в пространстве удержания и указывается в `word` .
  • Строка 2: это линия для поиска и замены в глобальном масштабе.

Команда sed :

 sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file 

Объяснение :

  • 1h; сохраните первую строку в пространстве удержания (это ожидание, которое мы хотим найти).
    • содержит пробел: word
  • 2{...} применяется ко второй строке.
  • x; обмен пространством рисунка и пространством удержания.
  • G; добавьте пространство удержания в пространство шаблона. В пространстве шаблонов мы имеем теперь:
 word # I will call this line the "pattern line" from now on line with a word and words and wording wordy words. 
  • :l; установите метку l как точку позже.
  • s/// выполнять фактический поиск / замену в пространстве шаблонов, упомянутом выше:
    • ^\([^\n]\+\)\n искать в «строке шаблона» для всех символов (начиная с начала строки ^ ), которые не являются символом новой строки [^\n] (один или несколько раз \+ ), до новой строки \n . Теперь это сохраняется в обратной ссылке \1 . Он содержит «линию рисунка».
    • (.*[^`]) искать любой символ .* за которым следует символ, который не является обратным шагом [^`] . Это сохраняется в \2 . \2 содержит: line with a word and words and wording wordy , до последнего появления word , потому что …
    • \1 является следующим поисковым термином (обратная ссылка \1 , word ), следовательно, что содержит «строка рисунка».
    • ([^`]) этим следует другой символ, который не является обратным; сохранен в ссылке \3 . Если мы этого не сделаем (и часть в \2 сверху), мы закончим бесконечный цикл, цитируя одно и то же word снова и снова -> ````word```` , потому что s/// всегда будет успешным и tl; перескакивает назад на :l (см. tl; далее вниз).
    • \1\n\2 \1 \3 все вышеперечисленное заменяется обратными ссылками. Второй \1 – тот, который мы должны процитировать (обратите внимание, что первая ссылка – это «линия рисунка»).
  • tl; если s/// был успешным (мы что-то заменили), переходим к метке l и начинаем заново, пока больше нечего искать и заменять. Это так, когда все вхождения слова заменяются / цитируются.
  • p; когда все будет сделано, напечатайте измененную строку (пространство рисунка).

Выход:

 $ sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file word line with a `word` and `word`s and `word`ing `word`y `word`s. 

Таблицы поиска могут быть сложными и дорогостоящими, потому что вам приходится одновременно искать оба конца пространства шаблонов. Однако, по крайней мере, он может быть реализован более или менее прямолинейно. Вы должны учитывать, что независимо от того, что вы делаете, вы можете надежно обрабатывать только одно совпадение за раз, и поэтому вы можете отказаться от всякой надежды на результат. Это все равно будет путать вещи – вы не работаете с скомпилированным выражением, вы буквально работаете с побочными эффектами и обеими сторонами для загрузки.

 printf %s\\n some words to match \ 'and some words and some more words to match them against' | sed -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \ -e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' 

Это основной цикл. На самом деле это не работает, потому что я еще не очищаю его, но он решает фундаментальную проблему. Поскольку вам приходится многократно перебирать одно и то же пространство шаблонов, как вы можете быть уверены, что ваш матч не соответствует дважды, не так ли? Если вы зарезервируете его с помощью какого-то разделителя, вы все равно будете снова совпадать, и вы просто будете складывать книжные знаки до бесконечности.

Решение, которое я использую здесь, заключается в том, чтобы помешать матчу. Я вставляю новую строку после первого символа матча, который мне все же нужно очистить, конечно, и с которым я буду справляться. Однако это все еще не работает, если ваши таблицы поиска могут содержать элементы, которые являются подмножествами других членов, или если вы работаете с одиночными наборами символов. Есть способы сделать это – и лучшие способы сделать это – и я предложу вам несколько альтернатив, если вы попросите их.

Вот еще немного:

 printf %s\\n some words to match \ 'and some words and some more words to match them against' | sed -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \ -e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' \ -el 

 and `s\nome` `w\nords` and `s\nome` more `w\nords` `t\no` `m\natch` \ them against\n\n\nsome\nwords\nto\nmatch\n$ 

Разумеется, очистка проста:

 printf %s\\n some words to match \ 'and some words and some more words to match them against' | sed -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \ -e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' \ -e 's/\(`.\)\n/\1/g;P' 

 and `some` `words` and `some` more `words` `to` `match` them against 

Это, по крайней мере, вы можете сделать g ложи.


Мой предпочтительный способ делать такие вещи – фактически создать для него скрипт.

 printf %s\\n some words to match \ 'and some words and some more words to match them against' | { sed -e"$( sed -ne'$w /dev/fd/3' -e$\q \ -e 's/[]\^$/.*[]/\\&/g' \ -e 's|..*|s/&/`\&`/g|p' )" <&3 } 3<<"" 3<>/dev/fd/3 

 and `some` `words` and `some` more `words` `to` `match` them against 

Команда sed в подстановке команд выписывает инструкцию sed s/// ubstitution после того, как она уберет любые метасимволы за любую строку ввода, но последняя может содержать. В последней строке это буквально распространяется на общий дескриптор файла здесь-doc для внешнего sed для чтения в качестве входных данных. Внутренний sed печатает сценарий, который работает как:

 sed -e's/some/`&`/g' \ -e's/words/`&`/g' \ -e's/to/`&`/g' \ -e's/match/`&`/g' 

… и протягивает последнюю строку к другому sed чтобы обработать потом.

  • Поведение POSIX привязок sed и $ regex с многострочными пространствами шаблонов
  • Как использовать команду sed для изменения записи файла в строке в сценарии оболочки?
  • Как использовать регулярное выражение с AWK для замены строки?
  • Как удалить первую точку перед первым номером?
  • Удалить строку с специальными символами
  • Как читать несколько строк вместо строк
  • Копировать файл при замене текста в нем
  • Как анализировать файл данных для извлечения определенных данных и формата для другого использования?
  • ksh / bash Форматирование файлов через sed по файлу cat | команда sed
  • сценарий оболочки для извлечения символов
  • Извлечь третью группу текста из разделителей диапазонов
  • Linux и Unix - лучшая ОС в мире.