Замените число из захвата regexp на вывод команды, используя это число в sed.

Вопрос или проблема

Я хочу перевести:

"a b c syscall=257 success=yes"

в следующее:

"a b c syscall=openat success=yes"

Я хотел бы использовать группирующий регулярное выражение sed и замену в сочетании с использованием ausyscall, применяемого к номеру, извлеченному группой регулярного выражения.

Я попробовал следующее в Linux/bash:

echo "a b c  syscall=257 success=yes" | sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall 257)":"

Это выводит: "a b c SYSCALL=openat success=yes", как и ожидалось.

Затем я попытался использовать захваченную группу #1 в качестве аргумента для ausyscall. Вот так:

echo "a b c  syscall=257 success=yes" | sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \1)":"

Это вызывает ausyscall 1, который выводит "write". Это не захваченная группа #1 (которая имеет значение 257).

Поэтому я попытался использовать \1 вместо этого, но это тоже не сработало:

echo "a b c  syscall=257 success=yes" | sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \\1)":"

Это вызывает ausyscall \1, поэтому это не сработало, выводит ошибку в stderr ("Unknown syscall \1 using x86_64 lookup table") и выводит "a b c SYSCALL= success=yes" в stdout.

Не удается передать захваченное значение в ausyscall. Я пробовал с одинарными кавычками, но тогда вызов ausyscall не выполняется.

Можно ли использовать sed таким образом?

Я только хочу знать, ожидается ли, что это возможно сделать с sed.

Я знаю, что это можно сделать другими способами (perl, python скрипт, gawk и т.д.), но я хочу увидеть, возможно ли это с sed и связано ли это с квотированием или чем-то подобным.

Возможно ли это с sed? Если да, что я упускаю?

Я не думаю, что sed может это сделать, но perl может и это лишь немного сложнее:

echo "a b c  syscall=257 success=yes" |
  perl -pe 's:syscall=(\d+):"SYSCALL=" . `ausyscall $1`:e'

Хотя это, вероятно, добавит дополнительную новую строку, что вам не нужно. Поэтому вам может понадобиться следующее:

echo "a b c  syscall=257 success=yes" |
  perl -pe 's:syscall=(\d+):chomp($v=`ausyscall "$1"`); sprintf "SYSCALL=$v" :e'

Оператор s в Perl работает практически так же, как и в sed. Единственное отличие здесь в том, что, используя флаг e в конце (s:old:new:e), это позволяет нам выполнять код Perl на стороне замены и использовать результат этого кода. Вопросный код:

  • ausyscall "$1": запуск ausyscall с передачей ему $1 (это эквивалент sed’s \1, хотя Perl также может работать с \1) в качестве аргумента.
  • chomp($v=...): удаление завершающих новых строк. Это удаляет новую строку, возвращаемую командой ausyscall. Результат хранится в переменной $v.
  • sprintf "SYSCALL=$v": это печатает желаемый вывод.

Не ожидается, что sed может это сделать. Он не может! Фактический запуск команды — это то, что делает ваша оболочка, а не sed, поэтому это не функция sed, а другой программы — оболочки.

Вы уже приближаетесь к этому! Вы используете интерпретатор языков скриптов в качестве двигателя замены, и внутри этого используете sed для выполнения нескольких элементарных операций. Ваша оболочка (будь то bash, ash, zsh, csh, cmd и т.д.) не отличается от, например, интерпретатора Python.

Ответ или решение

К сожалению, использование утилиты sed для выполнения команд и замены с использованием захваченных групп регулярных выражений невозможно. Основная причина заключается в том, что sed является текстовым редактором, который не имеет встроенных механизмов для вызова команд оболочки во время замены. Это ограничение связано с тем, что логика работы sed и логика работы командной строки (оболочки) различны.

Основные проблемы и ограничения sed

  1. Функциональность sed: sed предназначен для обработки и манипуляции текстовыми данными. Он использует регулярные выражения для поиска и замены, но не может выполнить внешние программы или команды в процессе работы.

  2. Отсутствие возможности обращения к внешним процессам: При попытке замены, например:

    echo "a b c  syscall=257 success=yes" | sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \1)":"

    sed не в состоянии интерпретировать \1 как захваченный шаблон при выполнении команды ausyscall. Вместо этого оболочка интерпретирует команду перед ее передачей в sed.

Альтернативные решения

Чтобы достичь желаемого результата, можно использовать более мощные инструменты, такие как perl, которые поддерживают подобную логику замены. Пример с perl будет выглядеть следующим образом:

echo "a b c  syscall=257 success=yes" |
  perl -pe 's:syscall=(\d+):"SYSCALL=" . `ausyscall $1`:e'

Этот вариант выполняет следующие операции:

  • Замена с использованием захваченной группы: При обнаружении подстроки syscall=257, perl захватывает 257.

  • Вызов команды: После этого происходит вызов команды ausyscall с полученным значением 257.

  • Устранение лишних символов: Поскольку вызов команды может вернуть лишний символ новой строки, можно использовать chomp для его удаления.

Вывод

В итоге, если вашей целью является использование захваченных значений для динамической подстановки в выходные данные, sed не является подходящим инструментом. Для такого рода задач лучше использовать perl, python или другие языки программирования, которые могут выполнять такие операции с более сложными логическими структурами.


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

Оцените материал
Добавить комментарий

Капча загружается...