пытаясь заменить строку в sed встроенными {
и $
и -E
или -r
, {
для меня проблематичен.
согласно документации и многим примерам, которые я прочитал, мне нужно будет избегать только {
и $
, если тестировать их. Я сократил простейший случай (ниже).
Наверное я чего-то не понимаю
Я могу использовать свой обходной путь, но это должно работать с \{
?
Данная строка:
: "${TARGET_PART:=${MMC_PART2}}"
и part=5
Я хочу заменить ${MMC_PART2}} на ${MMC_PART5}}
Не работает следующее:
echo ': "${TARGET_PART:=${MMC_PART2}}"'| sed -r "s/:=\{(MMC_PART).}}/\1$part}}/g"
но следующее работает - (заменено "{" на ".")
echo ': "${TARGET_PART:=${MMC_PART2}}"'| sed -r "s/:=.(MMC_PART).}}/\1$part}}/g"
Что мне не хватает?
Кроме того: -r
является аргументом в пользу включения ERE только в старых версиях GNU sed
. Современные версии GNU и BSD sed
используют -E
для включения ERE, как и grep
.
@EdMorton -E
также вошёл в последний стандарт - pubs.opengroup.org/onlinepubs/9799919799/utilities/sed.html
Проблема, с которой вы столкнулись, связана с тем, как sed интерпретирует специальные символы, такие как { и }, в расширенных регулярных выражениях (с -E или -r). В sed { и } используются для интервальных выражений, и их необходимо экранировать, если вы хотите сопоставить их буквально, даже если вы не используете их в контексте повторения шаблона.
В вашей первой команде sed { в шаблоне s/: = {(MMC_PART).}}/ интерпретируется как начало интервального выражения, а не как буквальная фигурная скобка.
Вот правильный способ справиться с этим:
1. Замените { и } обратной косой чертой, чтобы они соответствовали буквально.
Итак, ваша команда sed должна выглядеть так:
echo ': "${TARGET_PART:=${MMC_PART2}}"' | sed -r "s/:=\\{(MMC_PART)\\}\\}/:\\{\1$part\\}\\}/g"
Альтернативно, если вы хотите избежать побега:
2. Используйте sed без -E или -r и используйте обратную косую черту для всех специальных символов:
echo ': "${TARGET_PART:=${MMC_PART2}}"' | sed "s/:=\{MMC_PART2\}/:=\{MMC_PART$part\}/g"
Это гарантирует, что sed будет воспринимать { и } как буквальные символы, что позволит вам выполнить замену так, как предполагалось.
у "{" есть 2 обратные косые черты? //{ Я определенно что-то пропустил. Должно быть, это что-то типа bash.
@FloydBrown это мера предосторожности, позволяющая гарантировать, что bash передает команде буквальную обратную косую черту. В данном случае это не обязательно, но позволяет избежать необходимости помнить, когда это необходимо. bash обрабатывает доллар, обратную косую черту, обратную косую черту и иногда восклицательный знак как метасимволы, заключенные в двойные кавычки. The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or <newline>.
. POSIX sh делает то же самое: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
для 2. строка для sed должна быть "s/: = {MMC..."
, поскольку \{
включит обработку как диапазон, что здесь нежелательно
Чтобы расширить то, что говорит @jhnc, в этом ответе все наоборот: -E
/-r
не требует экранирования для {
, [
, +
и т. д.; sed без параметров делает. В этом разница между «базовыми» и «расширенными» регулярными выражениями POSIX. В GNU sed они различаются только тем, что нужно экранировать, а что нет.
Ваша команда sed синтаксически правильна, но не учитывает $
в:
: "${TARGET_PART:=${MMC_PART2}}"
Замена тоже кажется неправильной.
Первая команда должна быть:
part=5
echo ': "${TARGET_PART:=${MMC_PART2}}"'| sed -r "s/(:=\\\$\{MMC_PART).(}})/\1$part\2/g"
для вывода:
: "${TARGET_PART:=${MMC_PART5}}"
Обратите внимание, что внутри двойных кавычек обратную косую черту и доллар следует экранировать, чтобы избежать изменений в оболочке. Внутри одинарных кавычек это не обязательно:
echo ': "${TARGET_PART:=${MMC_PART2}}"'| sed -r 's/(:=\$\{MMC_PART).(}})/\1'"$part"'\2/g'
Ваша вторая команда не выполняет для меня никакой замены. Возможно, это было неправильно записано в вопросе.
См. здесь, чтобы узнать разницу между базовыми регулярными выражениями (BRE) и расширенными регулярными выражениями (ERE).