Какие символы мне нужно экранировать при использовании sed в скрипте sh?


248

Возьмите следующий скрипт:

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

Если я попытаюсь запустить это в sh( dashздесь), это потерпит неудачу из-за круглых скобок, которые должны быть экранированы. Но мне не нужно избегать обратной косой черты (между октетами или в \sили \1). Какое правило здесь? Как насчет того, когда мне нужно использовать {...}или [...]? Есть ли список того, что я делаю и не нужно убегать?


1
Вот функция bash для преобразования путей для использования с SED:function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
user2428118


Dura lex, sed sed
Немо

Ответы:


282

Здесь есть два уровня интерпретации: shell и sed.

В оболочке все между одинарными кавычками интерпретируется буквально, за исключением самих одинарных кавычек. Вы можете эффективно заключить одинарную кавычку в одинарные кавычки '\''(закрыть одинарную кавычку, одну буквальную одинарную кавычку, открыть одинарную кавычку).

Sed использует основные регулярные выражения . В BRE, чтобы их можно было трактовать буквально, символы $.*[\^должны быть заключены в кавычки, перед ними стоит обратная косая черта, за исключением внутренних наборов символов ( […]). Буквы, цифры и (){}+?|не должны быть заключены в кавычки (вы можете избежать цитирования некоторых из них в некоторых реализациях). Последовательности \(, \), \n, и в некоторых реализациях \{, \}, \+, \?, \|и другой обратный слэш + буквенно - цифровые имеют особое значение. Вы можете избежать неприятностей $^в некоторых позициях в некоторых реализациях.

Кроме того, вам нужен обратный слеш перед тем /, как он появится в регулярном выражении вне выражений в скобках. Вы можете выбрать альтернативный символ в качестве разделителя, написав, например, s~/dir~/replacement~или \~/dir~p; перед разделителем вам понадобится обратный слеш, если вы хотите включить его в BRE. Если вы выбираете символ, имеющий особое значение в BRE, и хотите включить его буквально, вам понадобится три обратных слеша; Я не рекомендую это, поскольку это может вести себя по-другому в некоторых реализациях.

В двух словах, для sed 's/…/…/':

  • Напишите регулярное выражение между одинарными кавычками.
  • Используйте, '\''чтобы закончить с одинарной кавычкой в ​​регулярном выражении.
  • Поставьте обратную косую черту перед $.*/[\]^и только этими символами (но не внутри скобочных выражений). (Технически вы не должны ставить обратную косую черту раньше, ]но я не знаю реализации, которая обрабатывает ]и \]отличается от скобочных выражений.)
  • Внутри выражения в скобках, -чтобы его можно было трактовать буквально, убедитесь, что оно первое или последнее ( [abc-]или [-abc]нет [a-bc]).
  • Внутри выражения в скобках, ^чтобы его можно было трактовать буквально, убедитесь, что оно не первое (используйте [abc^], а не [^abc]).
  • Чтобы включить ]в список символов, совпадающих с выражением в скобках, сделайте его первым символом (или первым после ^для отрицательного набора): []abc]или [^]abc](не [abc]]ни[abc\]] ).

В тексте замены:

  • &и \должны быть заключены в кавычки, перед ними стоит обратная косая черта, как и разделитель (обычно /) и символы новой строки.
  • \сопровождаемая цифра имеет особое значение. \сопровождаемая буквой имеет специальное значение (специальные символы) в некоторых реализациях, и \после нее следуют некоторые другие символьные средства \cили в cзависимости от реализации.
  • С одинарными кавычками вокруг аргумента ( sed 's/…/…/'), используйте, '\''чтобы поместить одинарную кавычку в текст замены.

Если регулярное выражение или текст замены происходит из переменной оболочки, помните, что

  • Регулярное выражение - это BRE, а не буквальная строка.
  • В регулярном выражении символ новой строки должен быть выражен как \n(который никогда не будет совпадать, если у вас нет другого sedкода, добавляющего символы новой строки в пространство шаблона). Но обратите внимание, что он не будет работать внутри скобочных выражений с некоторыми sedреализациями.
  • В тексте замены &, \и новые строки должны быть в кавычках.
  • Разделитель должен быть заключен в кавычки (но не внутри скобочных выражений).
  • Используйте двойные кавычки для интерполяции: sed -e "s/$BRE/$REPL/".

Экранируя символ подстановки (*), вы можете использовать двойную обратную косую черту ( \\*). Пример:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
danger89

43

Проблема, с которой вы столкнулись, заключается не в интерполяции и экранировании оболочки, а в том, что вы пытаетесь использовать расширенный синтаксис регулярного выражения, не передавая параметр sed -rили or --regexp-extended.

Измените свою линию sed с

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

в

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

и это будет работать, как я полагаю, вы собираетесь.

По умолчанию sed использует базовые регулярные выражения (думаю, стиль grep), для которых требуется следующий синтаксис:

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]

У меня снова возникла эта проблема, и я забыл прокрутить вниз, чтобы найти решение, за которое проголосовал в прошлый раз. Еще раз спасибо.
isaaclw

Большое спасибо. Добавление -rв качестве опции было то, что было необходимо в моем случае.
Здравствуйте, до свидания

15

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

Так что если вы хотите , чтобы увидеть СЕПГ s/\(127\.0\.1\.1\)\s/\1/ставить одиночные кавычки вокруг него и оболочка не будет касаться скобок или слэш в нем. Если вам нужно интерполировать переменную оболочки, поместите только эту часть в двойные кавычки. Например

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

Это избавит вас от необходимости запоминать, какие метасимволы оболочки не экранируются двойными кавычками.


Я хочу sedвидеть s/(127\.0\.1\.1)/..., но поместить это в сценарий оболочки как есть, не работает. То, что вы говорите о оболочке, не касающейся скобок, кажется неправильным. Я отредактировал свой вопрос, чтобы уточнить.
детально

3
Оболочка не касается скобок. Вам нужны обратные слэзы, потому что sed должен их видеть. sed 's/(127\.0\.1\.1)/IP \1/'не удается, потому что sed нужно видеть \(и \)для группового синтаксиса, а не (и ).
Кайл Джонс

facepalm Это не на странице руководства, но это есть в каком-то онлайн-руководстве, которое я нашел. Это нормально для регулярных выражений, потому что мне никогда не приходилось использовать его в библиотеках регулярных выражений (например, в Python)?
детально

3
Для традиционных команд Unix существуют базовые регулярные выражения и расширенные регулярные выражения. Подробности . sed использует базовые регулярные выражения, поэтому для группового синтаксиса необходимы обратные слэши. Perl и Python выходят за рамки даже расширенных регулярных выражений. Пока я копался, я обнаружил чрезвычайно информативную диаграмму, которая иллюстрирует, какой запутанный брамб мы вызываем, когда мы мельком говорим «регулярное выражение».
Кайл Джонс

1
Я также добавил бы, что единственный символ, который нельзя использовать внутри одинарных кавычек, это одинарные кавычки.
энзотиб
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.