Как выполнить тест регулярного выражения в bash, который начинается с пробелов и включает кавычки? - PullRequest
0 голосов
/ 23 апреля 2020

Я пытаюсь написать скрипт bash, который изменит цвет fill определенных элементов в файлах SVG. У меня нет опыта работы со сценариями оболочки, но я хорошо разбираюсь в регулярных выражениях (... в JS).

Вот тег SVG, который я хочу изменить:

<!-- is the target because its ID is exactly "the.target" -->
<path id="the.target" d="..." style="fill:#000000" />

Вот код bash, который я получил до сих пор:

local newSvg="" # will hold newly-written SVG file content
while IFS="<$IFS" read tag
do
    if [[ "${tag}" =~ +id *= *"the\.target" ]]; then
        tag=$(echo "${tag}" | sed 's/fill:[^;];/fill:${color};/')
    fi
    newSvg="${newSvg}${tag}"
done < ${iconSvgPath} # is an argument to the script

Объяснил: я использую read (разделение файла на < через пользовательский IFS) для чтения тега содержимого SVG по тегу Для каждого тега я проверяю, содержит ли он свойство id с точным значением, которое я хочу. Если этого не произойдет, я добавлю этот тег как есть в строку newSvg, которую позже напишу в файл. Если тег имеет желаемый идентификатор, я буду использовать sed для замены fill:STUFF; на fill:${myColor};. (Обратите внимание, что мой sed также не работает, но это не то, о чем я здесь спрашиваю.)

Не удается найти правильную строку с тестом [[ "${tag}" =~ +id *= *"the\.target" ]].

It успешно, если я изменю тест на [[ "${tag}" =~ \"the\.target\" ]].

Я не доволен рабочей версией, потому что она слишком хрупкая. Хотя я не намерен поддерживать all гибкостью XML, я бы хотел быть терпимым к семантически нерелевантным пробелам, а также к свойству id, находящемуся где-либо внутри тега. В идеале, регулярное выражение, которое я хотел бы написать, было бы express:

  • id (которому предшествует хотя бы один пробел)
  • , за которым следует ноль или более пробелов
  • , за которым следует =
  • , за которым следуют ноль или более пробелов
  • , за которыми следует "the.target"

Я думаю, что не правильно разграничиваю регулярное выражение внутри конструкции [[ ... =~ REGEX ]], но ни один из ответов, которые я видел в Интернете, не использует любые разделители вообще. В javascript литералы регулярных выражений ограничены (например, / +id *= *"the\.target"/), поэтому просто начать регулярное выражение с пробельного символа, который вас волнует. Кроме того, JS не имеет никаких магий c re: *, тогда как bash - это 50% магий c -обращение звездочек.

Любая помощь приветствуется. Мой план резервного копирования, возможно, попытаться использовать awk вместо этого (что я не лучше).


РЕДАКТИРОВАТЬ: мой sed был действительно близко. Я забыл добавить + после набора [^;]. Уф.

Ответы [ 3 ]

1 голос
/ 23 апреля 2020

Спасибо, что дали нам такой наглядный пример, что regex - это , а не способ решения этой проблемы.

Файл SVG представляет собой файл XML и возможный инструмент для их изменения: xmlstarlet .

Попробуйте этот скрипт, который я назвал modifycolor :

#!/bin/bash
# invoke as: modifycolor <svg.file> <target_id> <new_color>

xmlstarlet edit \
  --update "//path[@id = '$2']/@style" --value "fill:#$3" \
  "$1"

Предполагая, что файл SVG test.svg , вызовите его следующим образом:

./modifycolor test.svg the.target ff0000

Вы будете удивлены результатом.

Если вы хотите вставить кусок кода внутри bash скрипт, попробуйте это:

target="the.target"
newSvg=$(xmlstarlet edit \
  --update "//path[@id = '${target}']/@style" --value "fill:#${myColor}" \
  "${iconSvgPath}")
1 голос
/ 23 апреля 2020

Было бы намного проще, если бы вы определили шаблон регулярного выражения в переменной:

tag='      id  =   "the.target"'
pattern=' +id *= *"the\.target"'

if  [[ $tag =~ $pattern ]]; then
    echo matched.
fi
0 голосов
/ 23 апреля 2020

Спасибо людям за то, что они указали на ошибки в моем bash -fu, я придумал этот код, который делает то, что я сказал, что хотел. Я не буду отмечать это как принятый ответ, потому что, как отметили люди, регулярное выражение - плохой способ работать с XML. Разделите это для потомков.

local newSvg="" # will hold newly-written SVG code
while IFS="<$IFS" read tag
do
  if [[ "${tag}" =~ \ +id\ *=\ *\"the\.target\" ]]; then
    tag=$(echo "${tag}" | sed -E 's/fill:[^;]+;/fill:'"${color}"';/')
  fi
  newSvg="${newSvg}${tag}"
done < ${iconSvgPath}

Исправления:

  1. экранируйте пробел в регулярном выражении: =~ \ +id\ *=\ *
  2. для sed, переключитесь на двойной кавычки для переменной в шаблоне
  3. также для sed, я добавил флаг расширенного регулярного выражения -E, чтобы поддержать отмененный набор [^;]

Re: XML, я буду сравнивать список доступных CLI-дружественных парсеров XML с набором инструментов, обычно доступных на машинах моих пользователей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...