Вопрос или проблема
Я хочу перевести:
"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
-
Функциональность
sed
:sed
предназначен для обработки и манипуляции текстовыми данными. Он использует регулярные выражения для поиска и замены, но не может выполнить внешние программы или команды в процессе работы. -
Отсутствие возможности обращения к внешним процессам: При попытке замены, например:
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
для выполнения подобной задачи совершенно понятен, однако его ограничения превышают возможности этой утилиты, и это следует учитывать при выборе инструмента для автоматизации манипуляций с текстом. Если вам требуется помощь с другими инструментами или методами, не стесняйтесь обращаться!