почему экранирующие символы и регулярные выражения плохо работают с командой sed?

#bash #macos #sed

#bash #macos #sed

Вопрос:

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

 [heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/s /n/g"
abc  def    gks       dps
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/s{1,}/n/g"
abc  def    gkn       dpn
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ {1,}/n/g"
abcndefngksndps
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ {1,}/:/g"
abc:def:gks:dps
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/  /:/g"
abc  def    gks       dps
  

Но на самом деле работает только одно.

 [heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ {1,}/:/g"
    abc:def:gks:dps
  

Похоже, что s набор символов и специальный символ в регулярном выражении плохо работают с командой sed. И n не распознается как новая строка. Кто-нибудь может сказать мне, почему или дать какую-нибудь подсказку. Спасибо.

Ответ №1:

sed соответствует базовым регулярным выражениям, в то время как мета-символ взят из расширенных регулярных выражений. Сокращение s для символьного класса POSIX [[:space:]] будет работать только в некоторых sed (например, GNU sed) в качестве расширения. Аналогично n будет работать только в значении «новая строка» в некоторых sed, в то время как в любом sed вы можете использовать обратную косую черту, за которой следует буквальный символ новой строки. Использование double ( " ) вместо одинарных кавычек ( ' ) вокруг вашего скрипта подвергает его воздействию оболочки и, следовательно, требует дополнительных экранирований обратной косой черты — всегда используйте одинарные кавычки вокруг строк или скриптов, если у вас нет особой потребности в двойных кавычках (например, для расширения переменной), и используйте double, только если у вас нет особой необходимости в none (например, для разрешения расширения с помощью подстановочных знаков).

Чтобы делать то, что вы хотите в любом POSIX sed, нужно:

 $ echo 'abc  def    gks       dps' | sed 's/[[:space:]][[:space:]]*/
/g'
abc
def
gks
dps
  

но это будет работать с GNU sed (обратите внимание на -E включение ERES для — это поддерживается в GNU sed и OSX / BSD sed, но из этих 2 sed только GNU sed будет поддерживать s и n ):

 $ echo 'abc  def    gks       dps' | sed -E 's/s /n/g'
abc
def
gks
dps
  

Комментарии:

1. Вау, твой ответ больше похож на стандартное руководство для новичка вроде меня! Спасибо. Я постараюсь предпочесть одинарные кавычки двойным кавычкам.

Ответ №2:

Существует несколько проблем. Прежде всего, sed по умолчанию используются базовые регулярные выражения, которые не распознаются . Используйте -E модификатор для расширенных регулярных выражений, которые работают.

Во-вторых, sed не распознается n ; но вы можете использовать цитирование ANSI C, чтобы bash это было понятно. Однако, если вы просто используете n , у вас будет просто разрыв строки в вашем sed шаблоне, поэтому вам придется экранировать разрыв строки, чтобы sed использовать его буквально; таким образом, вам нужно \ для экранирования и n для разрыва строки в общей сложности три обратных косых черты.

Наконец, s класс символов также не распознается vanilla sed (но он доступен в GNU sed , который используется дистрибутивами Linux). Вместо этого используйте буквенный пробел, если вам нужна совместимость, например, с OSX (или brew install gnu-sed ).

 echo "abc  def    gks       dps" | sed -E $'s/  /\n/g'
# => abc
#    def
#    gks
#    dps
  

Комментарии:

1. Сэр, спасибо за ваше определенно четкое объяснение. Но s не поддерживается, это is….is странно.

2. Позвольте мне перефразировать: s поддерживается в gsed (GNU sed , которая по умолчанию sed установлена в Linux). Это не поддерживается на более старых, sed таких, например, как тот, который поставляется с OSX по умолчанию. sed имеет очень, очень долгую историю. Я отредактирую это в…

3. Хорошо, я понял. И еще один вопрос: зачем использовать доллар и одинарную кавычку? и особенно почему доллар? Я пытаюсь изменить его на sed -E «s / / \ n / g», и это становится хреновым. : )

4. $ thing — это инструкция bash, указывающая bash заменить строку n (или любую другую escape-последовательность) в том, что следует между ' s, буквальным переводом строки, прежде чем sed увидит скрипт. Итак, bash преобразует \n в <newline> , а затем sed видит всю команду целиком, поскольку s/ /<newline>/g' я бы не рекомендовал оборачивать весь скрипт таким образом, просто делайте это, когда абсолютно необходимо, для максимально краткого раздела, в данном случае sed -E 's/ /'$'n''/g' чтобы просто позволить n развернуться до буквального перевода строки, но не предоставлять остальную часть скрипта оболочке.

5. Спасибо, сэр. Для меня это новый способ ввода символа новой строки в командную строку оболочки. Прежде чем вы мне это скажете, я много лет использовал одинарную кавычку для ввода символа новой строки в оболочку. Большое вам спасибо. : )