Как я могу дать команду BSD sed интерпретировать escape-последовательности, такие как \ n и \ t?

14

У меня есть команда замены sed, которую я хотел бы совместить с BSD sedи GNU sed. Расширенные регулярные выражения не являются проблемой, так как они мне не нужны в этом случае. Моя основная проблема заключается в том, что эти две sedпары интерпретируют escape-последовательности символов в строках замены . Моя замена строка содержит вкладки и новую строку , и я хотел бы, чтобы они были видны в командных строках для удобства обслуживания, однако, BSD sedне интерпретируют управляющие последовательности и GNU sed делает . Как правильно sedинтерпретировать эти escape-последовательности в BSD? Следующие два фрагмента воплощают мою проблему:

GNU sed

echo ABC | sed 's/B/\n\tB\n'

yeilds

A
    B
C

BSD sed

echo ABC | sed 's/B\n\tB\n'

доходность

AntBnC

Очевидно, \nи \tне интерпретируются как escape-последовательности BSDsed

Теперь на мой вопрос. Согласно sedсправочной странице BSD :

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

Означает ли это, что мне нужно предшествовать буквальному переводу строки с помощью обратной косой черты? Как правильно sedинтерпретировать escape-последовательности, как \nв тексте замены?

ephsmith
источник
2
BSD sed не является GNU sed, и я не думаю, что он поддерживает такие экранированные символы в выходных данных. Вам нужно будет либо вставить буквенные символы, установить GNU sed или переключиться на что-то, что поддерживает такие экранированные символы, такие как awk.
jw013
@ jw013, у меня есть четкое различие между ними. Установка GNU SED не вариант. Я надеялся найти достаточно общих точек соприкосновения, чтобы достичь того, с чем я после sed. В конце концов, возможно, имеет смысл использовать awk. Так что вы думаете о толковании man-страницы BSD sed, которую я цитировал?
ephsmith
2
Да, вам нужно будет использовать буквенные табуляции и новые строки, а с помощью новых строк вам также нужно ставить перед ними обратную косую черту, которая по сути является просто механизмом продолжения строки.
jw013
@ jw013, спасибо за ваши великолепные ответы. На данный момент, ради обслуживания, я приму ваш совет и переделаю свое решение в awk.
ephsmith
Хороший выбор - awk - намного лучший план, чем принятый в настоящее время ответ :)
jw013

Ответы:

6

Если вам нужно написать переносимые сценарии, вы должны придерживаться функций в стандарте POSIX (он же Single Unix или Open Group Base Specification). Выпуск 7, также известный как POSIX-1.2008, является последним, но многие системы еще не приняли его. Выпуск 6, также известный как POSIX-1.2001 , предоставляется всеми современными организациями.

В sed значение escape-последовательностей, подобных \tи \nне переносимых, за исключением того, что в регулярном выражении , \nозначает новую строку. В тексте замены для sкоманды \nне является переносимым, но вы можете использовать последовательность backslash-newline для обозначения новой строки.

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

tab=$(echo | tr '\n' '\t')
escape=$(echo | tr '\n' '\033')
embolden () {
  sed -e 's/^/'"$escape"'[1m/' -e 's/$/'"$escape"'[0m/'
}

Отметьте еще раз, что переводы строк должны быть выражены по-разному в регулярных выражениях и в sтекстах замены.

Вы можете вместо этого использовать awk . Он позволяет использовать экранирование с обратной косой чертой, включая восьмеричные \ooo, в каждом строковом литерале.

Жиль "ТАК - перестань быть злым"
источник
7

Вы можете использовать кавычки bash, $'...'чтобы интерпретировать escape-символы перед передачей строки sed.

Со страницы руководства bash:

   Words  of  the  form  $'string'  are  treated specially.  The word
   expands to string, with backslash-escaped characters  replaced  as
   specified  by the ANSI C standard.  Backslash escape sequences, if
   present, are decoded as follows:
          \a     alert (bell)
          \b     backspace
          \e     an escape character
          \f     form feed
          \n     new line
          \r     carriage return
          \t     horizontal tab
          \v     vertical tab
          \\     backslash
          \'     single quote
          \nnn   the eight-bit character whose  value  is  the  octal
                 value nnn (one to three digits)
          \xHH   the eight-bit character whose value is the hexadeci-
                 mal value HH (one or two hex digits)
          \cx    a control-x character

   The expanded result is single-quoted, as if the  dollar  sign  had
   not been present.

   A  double-quoted  string  preceded by a dollar sign ($) will cause
   the string to be translated according to the current  locale.   If
   the  current locale is C or POSIX, the dollar sign is ignored.  If
   the string is translated and replaced, the replacement is  double-
   quoted.
Kevin
источник
3

На этот вопрос ответили на переполнение стека:

/programming/1421478/how-do-i-use-a-new-line-replacement-in-a-bsd-sed

Это в значительной степени именно то, что сказал jw013.

Для того, чтобы вставить буквенную вкладку типа ctrl+ VTab.

bahamat
источник
спасибо за ссылку. Я ненавижу, что мои поиски в Google не возвращали эту ссылку: D
ephsmith
1
Предложение ctrl-V tab зависит от оболочки, например, оно не будет работать в рыбе.
anddam
Никогда не использовал рыбу, я не знал, но приятно знать.
багамат