Comment puis-je demander à BSD sed d'interpréter les séquences d'échappement comme \ n et \ t?


14

J'ai une commande de remplacement sed que je voudrais être compatible avec BSD sedainsi que GNU sed. Les expressions régulières étendues ne sont pas un problème car je n'en ai pas besoin dans ce cas. Mon problème principal est la différence dans la façon dont les deux sedinterprètent les séquences d'échappement de caractères dans les chaînes de remplacement . Ma chaîne de remplacement contient des onglets et des sauts de ligne et j'aimerais qu'ils soient visibles dans les chaînes de commande pour faciliter la maintenance, cependant, BSD sedn'interprète pas les séquences d'échappement et GNU le sed fait . Quelle est la manière appropriée d'instruire sedpour interpréter ces séquences d'échappement sur BSD? Les deux extraits suivants résument mon problème:

GNOU sed

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

yeilds

A
    B
C

BSD sed

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

les rendements

AntBnC

De toute évidence, \net \tne sont pas interprétés comme des séquences d'échappement par BSDsed

Maintenant, à ma question. Selon la sedpage de manuel BSD :

Pour spécifier un caractère de nouvelle ligne dans la chaîne de remplacement, faites-le précéder d'une barre oblique inverse.

Cela implique-t-il que je devrais précéder une nouvelle ligne littérale d'une barre oblique inverse? Quelle est la manière appropriée d'instruire sedpour interpréter les séquences d'échappement comme \ndans le texte de remplacement?


2
BSD sed n'est pas GNU sed, et je ne pense pas qu'il supporte ces échappements dans la sortie. Vous devrez soit insérer des caractères littéraux, installer GNU sed, ou basculer vers quelque chose qui prend en charge de telles évasions comme awk.
jw013

@ jw013, je suis clair sur la différenciation entre les deux. L'installation de GNU sed n'est pas une option. J'espérais trouver suffisamment de terrain d'entente entre les deux pour accomplir ce que je recherchais sed. En fin de compte, il sera probablement judicieux d'utiliser awk. Alors, que pensez-vous de l'interprétation de la page de manuel BSD sed que j'ai citée?
ephsmith

2
Oui, vous devrez utiliser des tabulations littérales et des sauts de ligne, et avec les sauts de ligne, vous devez également les faire précéder d'une barre oblique inverse, qui est essentiellement un mécanisme de continuation de ligne.
jw013

@ jw013, merci pour vos bonnes réponses. À ce stade, pour des raisons de maintenance, je vais prendre vos conseils et retravailler ma solution en awk.
ephsmith

Bon choix - awk est un bien meilleur plan que la réponse actuellement acceptée :)
jw013

Réponses:


6

Si vous avez besoin d'écrire des scripts portables, vous devez vous en tenir aux fonctionnalités de la norme POSIX (alias Single Unix alias Open Group Base Specification). Le numéro 7 aka POSIX-1.2008 est le dernier, mais de nombreux systèmes n'ont pas encore fini de l'adopter. Le numéro 6 aka POSIX-1.2001 est généralement fourni par tous les appareils modernes.

Dans sed , le sens des séquences d'échappement comme \tet \nn'est pas portable, sauf que dans un regex , \nreprésente une nouvelle ligne. Dans le texte de remplacement d'une scommande, \nn'est pas portable, mais vous pouvez utiliser la séquence backslash-newline pour représenter une nouvelle ligne.

Une manière portable de générer un caractère de tabulation (ou tout autre caractère exprimé en octal) est avec tr. Stockez le caractère dans une variable shell et remplacez cette variable dans l'extrait sed.

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

Notez à nouveau que les nouvelles lignes doivent être exprimées différemment dans les expressions rationnelles et dans sles textes de remplacement.

Vous voudrez peut-être utiliser awk à la place. Il autorise les échappements à barre oblique inverse, y compris les échappements octaux \ooo, dans chaque chaîne littérale.


7

Vous pouvez utiliser la $'...'citation bash pour interpréter les échappements avant de passer la chaîne à sed.

Depuis la page de manuel de 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.

3

Cela a été répondu sur Stack Overflow:

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

C'est à peu près exactement ce que jw013 a dit.

Pour insérer un onglet littéral, tapez ctrl+ VTab.


merci pour la référence. Je déteste que mes recherches sur google n'aient pas renvoyé ce lien: D
ephsmith

1
La suggestion de l'onglet ctrl-V dépend du shell, par exemple, elle ne fonctionnera pas dans les poissons.
anddam

N'ayant jamais utilisé de poisson, je ne le savais pas, mais bon à savoir.
bahamat
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.