Скрипт Sed для поиска/замены внутри файлов .jsp. (от Struts до синтаксиса JSTL EL)

Мне нужен скрипт sed, который я могу использовать для 1) поиска экземпляров и 2) печати этой строки:

<bean:write name='iframesrcUrl'/> 
<bean:write name="iframesrcUrl"/>
<bean:write name="currentPage" property="title" filter="false"/>

или похожие. Значения name и property могут отличаться. Атрибуты property и filter являются необязательными. Встречаются как одинарные кавычки ', так и двойные кавычки ".

Команда sed должна быть двуглавой: я хочу сначала запустить одну команду, чтобы посмотреть, что она найдет. Затем я хочу запустить следующую команду, чтобы сделать фактические замены. Строки следует заменить на:

${ iframesrcUrl }
${ currentPage.title }

Быстрый grep показывает, что в моем проекте 68 вхождений: grep '<bean:write name=' **/* |wc -l

Что было бы самым простым способом решить эту проблему?


person Jesper Rønn-Jensen    schedule 22.12.2009    source источник


Ответы (4)


Узнав из других ответов, которые частично охватили мой вопрос, я пришел к следующему.

(Бьюсь об заклад, это можно сделать короче, но это работает) я пытаюсь найти все случаи появления таких конструкций, как

#my try to find every occurence of constructions like 
# <bean:write name='iframesrcUrl'/> 
# <bean:write name="iframesrcUrl"/>
# <bean:write name="currentPage" property="title" filter="false"/>
# 
# or similar. name and property values can differ. property and filter attributes are optional. 
# Both single quotes ' and double quotes " occur.
#
# cd jahia_virk/tomcat/webapps/ROOT/jsp/jahia/templates/virk/virk.dk


# Printing occurences:
# =====================
sed -nE \
-e '/<bean:write name="([[:alpha:]]+)"( property="([[:alpha:]]+)")( filter="false")?\/>/p' \
-e "/<bean:write name='([[:alpha:]]+)'( property='([[:alpha:]]+)')( filter='false')?\/>/p" \
-e '/<bean:write name="([[:alpha:]]+)"\/>/p' \
-e "/<bean:write name='([[:alpha:]]+)'\/>/p" \
*.jsp **/*.jsp **/*.inc  


# Replacing occurences:
# =====================
sed -E -i .bak \
-e 's/<bean:write name="([[:alpha:]]+)"( property="([[:alpha:]]+)")( filter="false")?\/>/${ \1.\3 }/g' \
-e "s/<bean:write name='([[:alpha:]]+)'( property='([[:alpha:]]+)')( filter='false')?\/>/\${ \1.\3 }/g" \
-e 's/<bean:write name="([[:alpha:]]+)"\/>/${ \1 }/g' \
-e "s/<bean:write name='([[:alpha:]]+)'\/>/\${ \1 }/g" \
*.jsp **/*.jsp **/*.inc 

Несколько извлеченных уроков:

  • $ зарезервировано из командной строки, поэтому мне пришлось избегать знака $ в строках, где выражение sed находится в двойных кавычках.
  • \w не работало для сопоставления любого символа слова. Поэтому мне пришлось заменить на [[:alpha:]]
  • Замены в любом файле в любом каталоге (*/* **/*) запрещены для скрытых системных файлов, двоичных файлов, таких как изображения и т. д. Мне пришлось сосредоточиться только на файлах .jsp и .inc для моего проекта: *.jsp **/*.jsp **/*.inc

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

Недостатки скрипта. По разным причинам следующие примеры не были найдены в приведенном выше скрипте:

<bean:write name='scriptEditor-Url'/>    
<bean:write name='currentSite' property='homePage.url'/>
<bean:write name="portlet" property="value" filter="false" />
<bean:write name='<%= "optTextUrl" + id %>'/>

# 1 не удалось, потому что [[:alpha:]] не соответствует - (а также есть некоторые с подчеркиванием).

#2 то же самое: [[:alpha:]] не соответствует точке ..

#4 объединяет строки внутри имени параметра. Я мог бы написать скрипт для их поиска, но в проекте их всего четыре. Большой вопрос, чем его заменить. Я подозреваю, что встроенная Java не работает. и я подозреваю, что не могу просто написать ${ 'optTextUrl' + id }

person Jesper Rønn-Jensen    schedule 22.12.2009

Я ухожу от вашего регулярного выражения grep здесь

1) Распечатать то, что он находит

sed '/<bean:write name=/!d'

2) Заменить то, что находит

sed '/<bean:write name=/s/^.*$/${ iframesrcUrl }\n${ currentPage.title }/'

Если посмотреть дальше на ваш вопрос, я вижу, что у вас, похоже, есть Bash4 с включенным globstar (из-за **/* glob). Если вы хотите, чтобы эти сценарии sed рекурсивно запускались для каждого файла, я бы предложил:

#!/bin/bash

for file in **/*; do
    <sed one-liner here> "$file"
done

Для замены сценария sed просто добавьте -i, чтобы выполнить редактирование на месте. Обратите внимание, что для этого требуется GNU sed. Если у вас нет GNU sed, вам придется перенаправить вывод во временный файл.

person SiegeX    schedule 22.12.2009
comment
Большое спасибо! Я обнаружил, что сопоставление одинарных и двойных кавычек из командной строки довольно сложно. Но это можно решить, используя два выражения и задав оба sed - person Jesper Rønn-Jensen; 22.12.2009

Предполагая, что у вас есть файл типа

<root>
<bean:write name='iframesrcUrl'/> 
<bean:write name="iframesrcUrl"/>
<bean:write name="currentPage" property="title" filter="false"/>
<foo><bar/></foo>
</root>

вы можете делать замены с помощью этой команды sed (используя GNU sed):

 sed "s/<bean:write name=[\'\"]\?iframesrcUrl[\'\"]\?\/>/\${ iframesrcUrl }/g; \
      s/<bean:write name=[\'\"]\?currentPage[\'\"]\?.*\/>/\${ currentPage.title }/g;" \
     input.xml

который производит:

<root>
${ iframesrcUrl } 
${ iframesrcUrl }
${ currentPage.title }
<foo><bar/></foo>
</root>

Это то, что вам нужно? Или вы хотите заменить значения атрибутов? Или вы хотите поместить свой текст замены в эти теги?

Чтобы найти и отредактировать все файлы на месте (внимание! Меняете файлы, пожалуйста, проверьте без -i перед использованием, поставьте свою маску файла вместо '*.jsp'):

find . -type f -name '*.jsp' -print0 | xargs -0 sed -i "..."

ОБНОВЛЕНИЕ

Чтобы заменить значения атрибутов, а не сами строки файла, я настоятельно рекомендую использовать xmlstarlet вместо sed/awk . Он намного надежнее и гибче. Я не могу опубликовать решение именно для вашего случая, потому что xmlstarlet нужен полный (действительный) файл для обработки, но это идея:

Учитывая файл:

<a>
   <b>
      <c name="foo"/>
      <c name="bar"/>
   </b>
</a>

Допустим, мы хотим заменить foo на SPAM и bar на EGGS. Затем эта команда сделает это (разделенные строки для удобства чтения):

$ printf '<a><b><c name="foo"/><c name="bar"/></b></a>' | \
  xmlstarlet ed --update "//c[@name='foo']/@name" -v SPAM \
                --update "//c[@name='bar']/@name" -v EGGS
<?xml version="1.0"?>
<a>
  <b>
    <c name="SPAM"/>
    <c name="EGGS"/>
  </b>
</a>

Я использовал синтаксис XPath для выбора элемента для замены (в первом случае это атрибут name, который принадлежит любому тегу c и равен foo). Подкоманда ed команды xmlstarlet позволяет выполнять различные преобразования, замена (обновление) элемента является лишь одним из них.

В реальных примерах вам нужно будет указать также bean workspace, т.е. добавить что-то вроде

 -N bean=urn:...

к списку вариантов xmlstarlet. Вы можете найти правильный URI в первых строках вашего файла .jsp (мне не на что смотреть).

person sastanin    schedule 22.12.2009
comment
Большое спасибо за ваши вдохновляющие идеи. Как вы уже догадались, я хотел заменить значения атрибутов. Часть на месте довольно тривиальна, потому что у меня все версии, поэтому легко отслеживать фактические изменения. - person Jesper Rønn-Jensen; 22.12.2009
comment
Тогда я бы рекомендовал использовать xmlstarlet. Я опубликую пример через несколько минут. - person sastanin; 22.12.2009

не совсем ясно, каким может быть ваш вывод. просто предположение, пока вы не предоставите более четкие образцы входных и выходных данных

awk '/bean:write name/{
    $0="${ iframesrcUrl }\n${ currentPage.title }"
}{print}' file
person ghostdog74    schedule 22.12.2009
comment
Спасибо например. Awk все еще немного пугает меня, потому что я не совсем понимаю сложные вещи, как в вашем примере выше. На данный момент я придерживаюсь версии sed. - person Jesper Rønn-Jensen; 22.12.2009
comment
сценарий awk просто говорит, что если имя bean:write найдено, эта строка должна быть изменена на ${iframesrcUrl}\n${currentPage.title}. \n - это новая строка. затем распечатайте запись. Это оно. - person ghostdog74; 23.12.2009