Output warna Bash gagal

8

Apakah ini masalah gema atau sed? Apa yang saya lakukan salah?

$> cat ~/bin/color_test.sh 
#!/bin/bash

ColorOff='\e[0m'       # Text Reset
BWhite='\e[1;37m'      # Bold White

string="test TEST test"
echo -e "$string" | sed -e "s/TEST/${BWhite}TEST${ColorOff}/g"

$> ~/bin/color_test.sh 
test e[1;37mTESTe[0m test

UJI dengan penyorotan tebal adalah apa yang diharapkan.

ДМИТРИЙ МАЛИКОВ
sumber

Jawaban:

11

sedtidak memperlakukan \esebagai urutan pelarian. Dengan sed GNU, dan sebagian besar implementasi sed lainnya di luar sana, \edalam steks pengganti hanya berarti e. Satu-satunya backslash yang dapat Anda gunakan dengan mudah dalam steks pengganti adalah \\backslash, \&berarti literal &, \/(di mana /karakter pembatas) untuk literal /, dan \1melalui \9untuk referensi-ulang. GNU sed dan BusyBox (tetapi tidak misalnya OpenBSD sed) menambahkan \nbaris baru. Dengan demikian output dari perintah sed Anda memiliki literal e.

Di bash, Anda dapat dengan mudah menempatkan karakter escape literal dalam variabel Anda dari awal. \eadalah salah satu urutan pelarian yang diakui oleh $'…'konstruk.

ColorOff=$'\e[0m'       # Text Reset
BWhite=$'\e[1;37m'      # Bold White
Gilles 'SANGAT berhenti menjadi jahat'
sumber
6

Ada dua masalah dalam echoperintah Anda .

Saya memperluas variabel untuk singkatnya.

$ echo -e "test TEST test" | sed -e "s/TEST/\e[1;37mTEST\e[0m/g"
test e[1;37mTESTe[0m test

Masalah pertama: backslash hilang di suatu tempat antara sihir sed dan sihir shell. Anda harus melarikan diri dari mereka.

$ echo -e "test TEST test" | sed -e "s/TEST/\\e[1;37mTEST\\e[0m/g"
test e[1;37mTESTe[0m test

Masih tidak berfungsi. Mungkin lebih banyak melarikan diri?

$ echo -e "test TEST test" | sed -e "s/TEST/\\\e[1;37mTEST\\\e[0m/g"
test \e[1;37mTEST\e[0m test

Akhirnya backslash akan datang. Saya tidak tahu mengapa kita membutuhkan tiga garis miring terbalik, itu adalah sihir sed yang aneh.

Masalah kedua: echo -etidak ada gunanya. -ememungkinkan interpretasi backslash lolos, tetapi semua echo -ebisa menafsirkannya "test TEST test". The backslash lolos berasal dari sed, yang tidak peduli tentang mereka dan mencetaknya mentah.

Yang Anda inginkan adalah ini:

$ echo -e $(echo "test TEST test" | sed -e "s/TEST/\\\e[1;37mTEST\\\e[0m/g")
test TEST test

dengan UJI tebal dalam output.

Berikut ini skrip lengkap dengan perubahan:

#!/bin/bash

ColorOff='\\\e[0m'       # Text Reset
BWhite='\\\e[1;37m'      # Bold White

string="test TEST test"
echo -e $(echo "$string" | sed -e "s/TEST/${BWhite}TEST${ColorOff}/g")
lesmana
sumber
Btw, echo -e "${BWhite}AAAA${ColorOff}"menunjukkan `\ AAAA`. Sayang sekali, karena daripada saya perlu menjaga regular_color_constants dan SED_color_constants. Sebenarnya, saya hanya ingin regular_color_constants, dan memperbaiki opsi echo dan sed untuk mendapatkan yang saya inginkan.
ДМИТРИЙ МАЛИКОВ
Solusi itu agak rapuh (bagaimana jika $stringmengandung backslash?) Dan sedikit lebih rumit dari yang diperlukan. Untuk memahami mengutip, ambil satu per satu. Misalnya tiga backslash sama sekali bukan sihir: pertama ada tanda kutip ganda, dan "\\\e"merupakan string dua karakter \e; kemudian ia mengerti \esebagai "karakter esecara harfiah".
Gilles 'SANGAT berhenti menjadi jahat'