Як зберегти складний регулярний вираз для багаторазового повторного використання в sed?


12

Використовуючи sed, я часто створюю досить складні і хитромудрі вирази, які мені потрібно двічі зіставити у файлі. Чи є спосіб я зберегти цей регулярний вираз і просто посилатись на нього двічі?

Може, щось таке виглядає?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Оновлення: Відповідь представила рішення використання bash змінної. Це не працює. Дано a test.txt.

#test.txt
foo bar
bar foo

І сценарій

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Це повинно дати результат

foo happy bar
bar foo

Але замість цього я отримую помилку

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Якщо ви використовуєте Perl, ви можете посилатися на попередні частини виразу у виразі:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman

1
Коли ви знайдете щось надто складне для sed, не соромтеся піти на awk або perl.
Жил 'ТАК - перестань бути злим'

2
@Cory: Ваш приклад працює чудово, якщо ви правильно розумієте його синтаксис. У вас "змінна $" все ще укладена в "одинарні лапки", що приховує її від розширення оболонки, яке ви очікуєте ... це повинно бутиsed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

Відповіді:


7

Ви можете використовувати змінні оболонки:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Я не впевнений у тому, що ви мали на увазі $i, але вам може знадобитися поставити його поза окремими цитатами:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Звичайно, це працює, лише якщо sedкоманда викликається з оболонки, але існує аналогічне рішення майже з усіма мовами програмування. (І я не думаю, що можна використовувати змінні всередині sed.)
Stéphane Gimenez,

Грн. Спробуючи це, схоже, що зворотні посилання виявляються порушеними. s/$complicated_regex/\1/видає помилку, кажучи, що це недійсна посилання.
Cory Klein

Ах, може бути, я винна, я звик до zsh змінних підстановок. Дивіться оновлену відповідь.
Stéphane Gimenez

Вам доведеться видалити якір із змінної і помістити їх у сценарій sed:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
glenn jackman

Да! Так, я забув перевірити, чи мені надано дійсне з'єднання з регулярними виразками :-)
Stéphane Gimenez

0

Найпростіший спосіб зменшити значення змінної оболонки sedі не турбуватися про те, як потрібно змінити ваш зворотний косий рисок для решти sedсценарію, - це скласти все в окремі лапки, крім змінної, і поставити це в подвійні лапки.

Усі наступні приклади коду передбачають: VALUE='foo \([a-z]\+\)'

Наступний зламаний код не вдається, оскільки змінна VALUEне розширюється:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Наступний зламаний код виходить з ладу, тому що зворотний косий \1рядок з'їдається оболонкою (тому що це в подвійних лапках, а не в одинарних лапках), перш ніж sedхтось побачить його

sed "s/${VALUE}/foo happy \1/" test.txt

Наступний код працює як очікується:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Наступний код також працює:

sed "s/${VALUE}/foo happy \\1/" test.txt

Так робиться наступне:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Але чому ускладнюється? Одиночні цитати навколо sedсценарію роблять все набагато зрозумілішим, особливо для тих, хто читає ваш код, гуру без сценаріїв. Мій прихильний шлях - знову ж таки, відмовитися від одинарних лапок, щоб подвоїти лапки тільки для змінної розширення та перейти назад до одинарних лапок:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.