Como instruir o BSD sed a interpretar seqüências de escape como \ n e \ t?

14

Eu tenho um comando de substituição sed que gostaria de ser compatível com o BSD sede o GNU sed. Expressões regulares estendidas não são um problema, pois não preciso delas neste caso. Meu principal problema é a diferença na maneira como os dois sedinterpretam as seqüências de escape de caracteres nas seqüências de caracteres de substituição . Meu cadeia de substituição contém guias e novas linhas e eu gostaria que eles sejam visíveis nas cadeias de comando para facilitar a manutenção, no entanto, BSD sednão interpreta as seqüências de escape e GNU sed faz . Qual é a maneira apropriada de instruir sedpara interpretar essas seqüências de escape no BSD? Os dois trechos a seguir resumem meu problema:

GNU sed

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

yeilds

A
    B
C

BSD sed

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

rendimentos

AntBnC

Claramente, \ne \tnão são interpretados como seqüências de escape pelo BSDsed

Agora, a minha pergunta. De acordo com a página de sedmanual do BSD :

Para especificar um caractere de nova linha na sequência de substituição, preceda-o com uma barra invertida.

Isso implica que eu precisaria preceder uma nova linha literal por uma barra invertida? Qual é a maneira apropriada de instruir sedpara interpretar seqüências de escape como \nno texto de substituição?

ephsmith
fonte
2
O BSD sed não é o GNU sed, e eu não acho que ele suporte essas fugas na saída. Você precisará inserir caracteres literais, instalar o GNU sed ou mudar para algo que suporte tais escapes, como o awk.
Jw013
@ jw013, eu sou claro na diferenciação entre os dois. Instalar o GNU sed não é uma opção. Eu esperava encontrar um terreno comum suficiente entre os dois para realizar o que estou procurando sed. No final, provavelmente fará sentido usar o awk. Então, o que você acha da interpretação da página de manual do BSD sed que citei?
ephsmith
2
Sim, você precisará usar guias e novas linhas literais e, com as novas linhas, também precisará precedê-las com uma barra invertida, que é basicamente apenas um mecanismo de continuação de linha.
Jw013
@ jw013, obrigado por suas ótimas respostas. Neste ponto, para a manutenção do bem, vou seguir seus conselhos e refazer minha solução no awk.
ephsmith
Boa escolha - awk é um plano melhor tanto do que a resposta atualmente aceita :)
jw013

Respostas:

6

Se você precisar escrever scripts portáteis, deve se ater aos recursos do padrão POSIX (também conhecido como Single Unix ou Open Group Base Specification). A edição 7, também conhecida como POSIX-1.2008, é a mais recente, mas muitos sistemas ainda não terminaram de adotá-la. A edição 6, também conhecida como POSIX-1.2001, é geralmente fornecida por todos os órgãos modernos.

No sed , o significado de seqüências de escape como \te \nnão é portátil, exceto que em uma regex , \nsignifica uma nova linha. No texto de substituição de um scomando, \nnão é portátil, mas você pode usar a sequência barra invertida-nova linha para representar uma nova linha.

Uma maneira portátil de gerar um caractere de tabulação (ou qualquer outro caractere expresso em octal) é com tr. Armazene o caractere em uma variável de shell e substitua essa variável no snippet sed.

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

Observe novamente que as novas linhas precisam ser expressas de maneira diferente nas regexes e nos stextos de substituição.

Você pode querer usar o awk . Permite escapes de barra invertida, incluindo escapes octais \ooo, em cada literal de string.

Gilles 'SO- parar de ser mau'
fonte
7

Você pode usar as $'...'citações do bash para interpretar as fugas antes de passar a string para sed.

Na página do manual do 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
fonte
3

Isso foi respondido no Stack Overflow:

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

É exatamente o que jw013 disse.

Para inserir uma guia literal, digite ctrl+ VTab.

bahamat
fonte
obrigado pela referência. Eu odeio que minhas pesquisas do Google não retornou que link: D
ephsmith
1
A sugestão da guia ctrl-V depende do shell, por exemplo, não funciona em peixes.
anddam
Como nunca usei peixe, eu não sabia, mas é bom saber.
bahamat