Выражение динамической подстановки Sed throws: unmatched '|' - PullRequest
0 голосов
/ 05 мая 2018

У меня есть уменьшенный JS-файл. Содержит специальные символы, такие как трубы, тире, косые черты и т. Д.

Кроме того, у меня есть еще один HTML-файл, который содержит комментарий внутри:

<!--#MY_SNIPPET#-->

Я пытаюсь использовать sed, чтобы добавить мой js-файл и заменить его комментарием выше.

Пример my.js

<script>whatever|@</script><script>-my</script>

Я сейчас занимаюсь:

VARIABLE=$(cat my.js)
sed -i "s|<!--#MY_SNIPPET#-->|${VARIABLE}|" index.html

Но я получаю sed: unmatched '|'

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

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

Ответы [ 3 ]

0 голосов
/ 05 мая 2018

Никогда не заключайте весь сценарий в двойные кавычки, так как вы затем подвергаете весь сценарий оболочке для интерпретации, и это может иметь непредвиденные последствия, которые вы испытываете прямо сейчас. Открывайте сценарий для оболочки, только если / когда вам нужна оболочка для выполнения конкретной задачи, например, расширить переменную в вашем случае. Заключайте сценарии в одинарные кавычки, а не в двойные.

Итак, не пишите:

sed -i "s|<!--#MY_SNIPPET#-->|${VARIABLE}|" index.html

напишите это вместо:

sed -i 's|<!--#MY_SNIPPET#-->|'"${VARIABLE}"'|' index.html

Теперь ваша следующая проблема - VARIABLE содержит разделитель, который вы используете в своем скрипте, |. Чтобы это исправить, просто измените разделитель в сценарии, например, от | до ~:

sed -i 's~<!--#MY_SNIPPET#-->~'"${VARIABLE}"'~' file

Это будет "работать", пока VARIABLE не содержит ~, & или \<number> символов / строк. Для более надежного решения вам нужно сделать то, что показано на Можно ли надежно экранировать метасимволы регулярных выражений с помощью sed или переключиться на awk, поскольку awk может работать с литеральными строками, а sed не может.

0 голосов
/ 05 мая 2018

Независимо от того, какой разделитель вы используете для команды s///, существует риск, что ваша переменная может содержать этот символ. Лучше всего избегать использования любого такого символа в переменной:

$ var='<script>whatever|@</script><script>-my</script>'
$ echo "${var//|/\\|}"
<script>whatever\|@</script><script>-my</script>
# ..............^^

тогда

sed -i "s|<!--#MY_SNIPPET#-->|${var//|/\\|}|" index.html
0 голосов
/ 05 мая 2018

Построение динамического выражения sed может быть трудным, если не невозможным, в некоторых случаях. У вас две проблемы: восклицательный знак ! внутри (или снаружи) двойных кавычек имеет специальное назначение bash, например, попробуйте это на консоли

!! Этот повторяет последнюю выполненную команду (будьте осторожны!: D)
echo "!$" выводит последний аргумент предыдущей команды
!5087 выполнить команду 5087 в вашей истории bash.

Другая проблема big заключается в том, что ваша переменная может содержать практически любой символ, поэтому вы не можете быть уверены, что разделителя выражений sed там нет, для вашего конкретного примера это работает

sed -ri "s~<[!]--#MY_SNIPPET#-->~${var}~" test.html

PS: разделитель должен быть однобайтовым символом: (

sed -ri "sЖ<[!]--#MY_SNIPPET#-->Ж${var}Ж" test.html

sed: -e expression #1, char 2: delimiter character is not a single-byte character

Еще одним измененным вариантом может быть замена выбранного разделителя в VARIABLE и его восстановление

sed -ri "s@<[!]--#MY_SNIPPET#-->@$(echo "${var}" | tr '@' 'ж')@" test.html
cat test.html | tr 'ж' '@' > test2.html
mv test2.html test.html
...