Замена "../../../" с помощью sed - PullRequest
0 голосов
/ 03 января 2019

У меня есть текстовый файл, который нужно отредактировать.Первое поле содержит строку

"../../../"

, и я хочу заменить на

"/ home"

.Я пытался использовать sed, но ... и / - это специальные символы, и я немного запутался, как подобрать эти шаблоны.Я пытался использовать что-то вроде (..), но, похоже, не работает для моего случая.Может ли кто-нибудь помочь мне понять, как подобрать такую ​​модель?

Ответы [ 4 ]

0 голосов
/ 05 января 2019

Мы можем использовать регулярные выражения для получения желаемого результата.

echo "../../../" | sed -r 's/(..\/){3}/\/home/g'

Опция детали

В соответствии с man page из sed

-E, -r, --regexp-extended

использовать в скрипте расширенные регулярные выражения (для переносимости используйте POSIX -E).

REGEXПодробности

(../) {3} : Это обеспечит "../../../"

Как мы используем (/) в sed отл.sed 's /// g', поэтому мы не можем использовать normal (/) в sed, поэтому нам нужно экранировать этот символ в (/)

, так как это относится к (../) 3 раза.Если вы хотите изменить все (../), добавьте * вместо {3}.ех.(../)*

/ home: дает "/ home"

Если вы хотите еще один (/) после дома, вы можете добавить (/ home /)

sed -r 's / (../){3} / /home / g'

Так что мы просто заменяем "/ home" вместо "../../../".Теперь вы можете изменить его в соответствии со своими потребностями.

0 голосов
/ 03 января 2019

Косая черта / и точка . являются специальными символами регулярного выражения для sed, поэтому их необходимо экранировать, если они используются для своих буквенных символов.
Точка - это подстановочный знак из одного символа, поэтому .. соответствует любым двум символам , а не буквальным двум точкам.
Косая черта разделяет поиск, замену и флаги, как man-страница для состояний sed /regular expression/replacement/flags - так что ваш шаблон поиска должен избегать обоих, делая его

sed 's/\.\.\/\.\.\/\.\./home/g' file > newfile

Это довольно уродливо, но sed может использовать что-то отличное от / в качестве разделителя. Мой любимый альтернативный вариант - ~, поэтому команда станет

sed 's~\.\./\.\./\.\.~home~g' file > newfile

Обновление
Отвечая на комментарий @Gu Buddy ...

Я не знаю, что это "более элегантно", но есть и другие способы подойти к этому.

Специальные символы, такие как . * /, теряют свое специальное значение при использовании в классе символов, поэтому [.] просто означает period , а не «любой символ», так что вы можете избежать их

sed 's/[.][.][/]/dot-dot-slash/g' file
sed 's/[.][.][/][.][.][/][.][.]/home/g' file

Вы также можете использовать счетчик совпадений (повторений) - число или диапазон в фигурных скобках, применяемый к предшествующему ему символу или группе - но их необходимо экранировать, если вы не используете расширенные регулярные выражения («ERE» против базового регулярного выражения «BRE»), включается с помощью флага -E:

    sed 's~\([.][.][/]\)\{3\}~home/~' file  # with BRE
group start-^  grp end-^  ^-count
    sed -E 's~([.][.][/]){3}~home/~' file   # with ERE
    sed -E 's~([.]{2}[/]){3}~home/~' file   # also ERE

Обратите внимание, что в моем исходном ответе я избегал замены третьего слеша, оставляя его там, чтобы отделить замену "home" от оставшегося пути ...

../../../
        ^

... но при использовании повторения {3} он совпадет и заменит этот третий слеш, поэтому я должен включить слеш после home в строке замены.

Я проверил все это на файле, который просто содержит это:

../../../this/that/file.txt
../../../some/otherfile.txt

получить этот вывод:

home/this/that/file.txt
home/some/otherfile.txt
0 голосов
/ 03 января 2019

Символ . рассматривается sed как подстановочный знак, поэтому его необходимо экранировать.Вам также понадобится экранировать символ / , если вы используете его в качестве разделителя:

sed 's/\.\.\/\.\.\/\.\.\//\/home/g'
#     ^                  ^      ^  <-- locations of '/' delimiters
#          ^^    ^^    ^^ ^^       <-- locations of '\/' to match literal '/' characters

Первый символ, который вы указали для sed, используется в качестве разделителя.Если ваше регулярное выражение выглядит как /.../.../ или s/.../.../, то разделитель становится /.Если вы замените этот разделитель / чем-то другим, вам не нужно экранировать буквальный символ '/', который вы ищете (или заменить на):

# Same as above, but with delimiters swapped from '/' to '@':
sed 's@\.\.\/\.\.\/\.\.\/@\/home@g'
#     ^                  ^      ^  <-- locations of '@' delimiters
#          ^^    ^^    ^^ ^^       <-- locations of '\/' to match literal '/' characters

Теперь с @ используется в качестве разделителей вместо /, вы можете упростить / переписать это с меньшим количеством экранированных / символов:

sed 's@\.\./\.\./\.\./@/home@g'
#     ^               ^     ^  <-- locations of '@' delimiters
#          ^    ^    ^ ^       <-- locations of literal '/' characters

Примечание:

К сожалению,\. не очень читабелен, но необходим, чтобы у вас не было такого типа краевого регистра:

$ echo 'ab/../cd/' | sed 's@../../../@/home@g'
/home

Вышеприведенное СЛЕДУЕТ оставить без изменений:

$ echo 'ab/../cd/' | sed 's@\.\./\.\./\.\./@/home@g'
ab/../cd/
0 голосов
/ 03 января 2019

Вам необходимо избежать косых черт и точек:

sed 's/\.\.\/\.\.\/\.\./\/home/g' file.txt > newfile.txt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...