Come posso dare istruzioni a BSD sed di interpretare le sequenze di escape come \ n e \ t?


14

Ho un comando di sostituzione sed che vorrei essere compatibile con BSD sede GNU sed. Le espressioni regolari estese non sono un problema in quanto non ne ho bisogno in questo caso. Il mio problema principale è la differenza nel modo in cui i due sedinterpretano le sequenze di escape dei caratteri nelle stringhe di sostituzione . La mia stringa di sostituzione contiene tab e newline e vorrei che fossero visibili nelle stringhe di comando per facilità di manutenzione, tuttavia BSD sednon interpreta le sequenze di escape e GNU lo sed fa . Qual è il modo appropriato per istruire seda interpretare queste sequenze di escape su BSD? I seguenti due frammenti rappresentano il mio 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'

i rendimenti

AntBnC

Chiaramente, \ne \tnon sono interpretati come sequenze di escape da BSDsed

Ora, alla mia domanda. Secondo la sedmanpage BSD :

Per specificare un carattere di nuova riga nella stringa di sostituzione, precederlo con una barra rovesciata.

Ciò implica che avrei bisogno di precedere una nuova riga letterale da una barra rovesciata? Qual è il modo appropriato per istruire sedl'interpretazione delle sequenze di escape come \nnel testo sostitutivo?


2
BSD sed non è GNU sed e non credo che supporti tali fughe nell'output. Dovrai inserire caratteri letterali, installare GNU sed o passare a qualcosa che supporti tali escape come awk.
jw013,

@ jw013, sono chiaro sulla differenziazione tra i due. L'installazione di GNU sed non è un'opzione. Speravo di trovare abbastanza terreno comune tra i due per realizzare quello che sto cercando sed. Alla fine probabilmente avrà senso usare awk. Cosa ne pensi dell'interpretazione della manpage di BSD sed che ho citato?
ephsmith

2
Sì, dovrai usare tab e letterline letterali e con le newline devi anche precederli con una barra rovesciata, che è fondamentalmente solo un meccanismo di continuazione della linea.
jw013,

@ jw013, grazie per le tue ottime risposte. A questo punto, per la manutenzione, prenderò il tuo consiglio e rielaborerò la mia soluzione in awk.
ephsmith

Buona scelta - awk è un piano molto migliore della risposta attualmente accettata :)
jw013

Risposte:


6

Se è necessario scrivere script portatili, è necessario attenersi alle funzionalità dello standard POSIX (aka Single Unix aka Open Group Base Specification). Il numero 7 aka POSIX-1.2008 è l'ultimo, ma molti sistemi non hanno ancora finito di adottarlo. Il numero 6 aka POSIX-1.2001 è generalmente fornito da tutti i moderni unici.

In sed , il significato delle sequenze di escape piace \te \nnon è portatile, tranne che in una regex , \nsta per una nuova riga. Nel testo sostitutivo di un scomando, \nnon è portatile, ma è possibile utilizzare la sequenza backslash-newline per indicare una nuova riga.

È disponibile un modo portatile per generare un carattere di tabulazione (o qualsiasi altro carattere espresso in ottale) tr. Memorizza il personaggio in una variabile shell e sostituisci questa variabile nello snippet di sed.

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

Si noti ancora che le nuove righe devono essere espresse in modo diverso nelle regex e nei stesti sostitutivi.

Invece potresti voler usare awk . Consente fughe di barra rovesciata, comprese fughe ottali \ooo, in ogni stringa letterale.


7

È possibile utilizzare la $'...'citazione bash per interpretare le escape prima di passare la stringa a sed.

Dalla pagina man di 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

A questo è stato risposto su StackTranslate.it:

https://stackoverflow.com/questions/1421478/how-do-i-use-a-new-line-replacement-in-a-bsd-sed

È praticamente esattamente quello che ha detto jw013.

Per inserire una scheda letterale digitare ctrl+ VTab.


grazie per il riferimento. Odio che le mie ricerche su Google non abbiano restituito quel link: D
ephsmith

1
Il suggerimento della scheda ctrl-V dipende dalla shell, ad esempio non funzionerà nei pesci.
anddam,

Non avendo mai usato il pesce non ero a conoscenza, ma buono a sapersi.
Bahamat,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.