Просто для удовольствия, вот еще одно решение, использующее только sed
. (Нет веских оснований для использования sed
в производстве, когда доступны лучшие инструменты; это все же хорошее упражнение.)
Сравните с простым и кратким решением, опубликованным Энрико Де Анжелисом. Есть два различия между его подходом и тем, что я предлагаю ниже.
Во-первых, подход в ответе Энрико не сработает, если текст «замены» включает пробелы (если, например, каждый пробел должен быть заменен на % 20
с пробелом после знака процента). Конечно, в проблеме ОП это не так; но в более общей задаче циклический подход в решении Энрико может привести к бесконечным циклам.
Во-вторых, циклический подход требует одного прогона соответствия регулярному выражению для каждого пространства, которое должно быть заменено. В отличие от этого, хотя приведенное ниже решение также запускает команду s
несколько раз, это фиксированное число запусков на строку ввода независимо от количества заменяемых пробелов. Опять же, в проблеме OP это не проблема, потому что в каждой строке очень мало мест для замены. Приведенный ниже подход может быть полезен в более общих ситуациях, когда в каждой строке требуется большое количество замен.
Идея относительно проста, но решение осложняется тем, что sed
имеет только два буфера, с которыми мы можем работать. Переключаясь между ними, мы можем «сохранить» часть строки, к которой нам не нужно прикасаться, и внести изменения в оставшуюся строку. Поскольку у нас есть только два буфера и три соответствующие подстроки, мы вынуждены внести «слишком много изменений» в первой половине решения, а затем отменить ненужные изменения во второй половине. Это решение также имеет явный недостаток: если в последней части строки уже было %20
(после закрывающей двойной кавычки, относящейся к folder
), они будут заменены на пробел, даже если они не были пробелами в оригинал.
Интересно, есть ли лучшие подходы в этом направлении (имеется в виду, в частности, не связанные с циклическим процессом).
$ sed -E '/folder:"/{h;s/(^.*?folder:").*/\1/;x;s/^.*?folder:"//;s/ /%20/g;x;G;
> /folder:"/s/\n//;h;s/(^.*?folder:"[^"]*").*/\1/;x;s/.*?folder:"[^"]*"//;
> s/%20/ /g;x;G;/folder:"/s/\n//}' inputfile
Как обычно, ведущие $
и >
- это приглашения оболочки (не являются частью команды sed
).
EDIT Как отмечает Эд Мортон в комментарии ниже, ленивые квантификаторы являются функцией perl, не поддерживаются в sed
. Это не было важной частью моего решения; Вот POSIX ERE - совместимая версия:
$ sed -E '/folder:"/{h;s/(^.*folder:").*/\1/;x;s/^.*folder:"//;s/ /%20/g;x;G;
> /folder:"/s/\n//;h;s/(^.*folder:"[^"]*").*/\1/;x;s/.*folder:"[^"]*"//;
> s/%20/ /g;x;G;/folder:"/s/\n//}' inputfile