Bagaimana saya bisa menginstruksikan sed BSD untuk menafsirkan urutan melarikan diri seperti \ n dan \ t?

14

Saya memiliki perintah penggantian sed yang saya ingin kompatibel dengan BSD sedserta GNU sed. Ekspresi reguler yang diperluas bukan masalah karena saya tidak membutuhkannya dalam kasus ini. Masalah utama saya adalah perbedaan dalam cara kedua sedkarakter menafsirkan urutan pelarian dalam string pengganti . String pengganti saya berisi tab dan baris baru dan saya ingin agar terlihat di string perintah untuk kemudahan pemeliharaan, namun, BSD sedtidak menafsirkan urutan pelarian dan GNU sed melakukannya . Apa cara yang tepat untuk menginstruksikan seduntuk menafsirkan urutan melarikan diri ini pada BSD? Dua snippet berikut melambangkan masalah saya:

GNU sed

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

yeilds

A
    B
C

BSD sed

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

hasil panen

AntBnC

Jelas, \ndan \ttidak ditafsirkan sebagai urutan pelarian oleh BSDsed

Sekarang, untuk pertanyaan saya. Menurut sedmanual BSD :

Untuk menentukan karakter baris baru dalam string pengganti, awali dengan garis miring terbalik.

Apakah ini menyiratkan bahwa saya harus mendahului baris baru literal dengan garis miring terbalik? Apa cara yang tepat untuk menginstruksikan seduntuk menafsirkan urutan melarikan diri seperti \ndalam teks pengganti?

ephsmith
sumber
2
BSD sed bukan GNU sed, dan saya tidak berpikir itu mendukung lolos seperti itu di output. Anda harus memasukkan karakter literal, menginstal GNU sed, atau beralih ke sesuatu yang mendukung pelarian seperti awk.
jw013
@ jw013, saya jelas tentang perbedaan antara keduanya. Menginstal GNU sed bukan pilihan. Saya berharap menemukan cukup kesamaan di antara keduanya untuk mencapai apa yang saya inginkansed . Pada akhirnya mungkin masuk akal untuk menggunakan awk. Jadi apa yang Anda pikirkan tentang interpretasi dari sed sedpage BSD yang saya kutip?
ephsmith
2
Ya, Anda harus menggunakan tab literal dan baris baru, dan dengan baris baru Anda juga harus mengawalinya dengan backslash, yang pada dasarnya hanya mekanisme garis-kelanjutan.
jw013
@ jw013, terima kasih atas balasan Anda yang luar biasa. Pada titik ini, demi pemeliharaan, saya akan menerima saran Anda dan mengerjakan ulang solusi saya dengan awk.
ephsmith
Pilihan yang baik - awk adalah rencana yang jauh lebih baik daripada jawaban yang saat ini diterima :)
jw013

Jawaban:

6

Jika Anda perlu menulis skrip portabel, Anda harus tetap menggunakan fitur-fitur dalam standar POSIX (alias Single Unix alias Open Group Base Specification). Edisi 7 alias POSIX-1.2008 adalah yang terbaru, tetapi banyak sistem belum selesai mengadopsinya. Edisi 6 alias POSIX-1.2001 pada umumnya disediakan oleh semua kesatuan modern.

dalam sed , makna urutan escape seperti \tdan \ntidak portabel, kecuali bahwa dalam regex , \nsingkatan baris baru. Dalam teks pengganti untuk sebuah sperintah, \ntidak portabel, tetapi Anda dapat menggunakan urutan backslash-newline untuk berdiri untuk baris baru.

Cara portabel untuk menghasilkan karakter tab (atau karakter lain yang dinyatakan dalam oktal) adalah dengan tr. Simpan karakter dalam variabel shell dan gantikan variabel ini dalam potongan sed.

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

Perhatikan lagi bahwa baris baru harus diekspresikan secara berbeda dalam regex dan dalam steks pengganti.

Anda mungkin ingin menggunakan awk sebagai gantinya. Ini memungkinkan lolos backslash, termasuk lolos oktal\ooo , di setiap string literal.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
7

Anda dapat menggunakan bash $'...' kutipan untuk menafsirkan lolos sebelum meneruskan string sed.

Dari halaman bash man:

   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
sumber
3

Ini telah dijawab pada Stack Overflow:

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

Ini persis seperti yang dikatakan jw013.

Untuk memasukkan tipe tab literal ctrl+ VTab.

bahamat
sumber
terima kasih untuk referensi. Saya benci pencarian google saya tidak mengembalikan tautan itu: D
ephsmith
1
Saran tab ctrl-V bergantung pada shell, misalnya itu tidak akan berfungsi pada ikan.
anddam
Karena tidak pernah menggunakan ikan, saya tidak menyadari, tetapi senang untuk tahu.
bahamat