Menggunakan variabel untuk menyimpan kode warna terminal untuk PS1?

33

Di saya .bashrc, saya menggunakan kode warna terminal ANSI untuk mewarnai berbagai bit. Ini terlihat seperti ini:

PS1='\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ '

di mana virtual_envdan git_branchadalah fungsi bash yang menampilkan barang di stdout.

Sekarang, untuk membuatnya lebih mudah dibaca dan dimodifikasi, saya ingin menyimpan kode warna dalam variabel dan merujuknya, alih-alih menanamkannya langsung ke PS1. Jadi saya punya banyak variabel seperti ini:

GREEN="\[\033[32m\]"
YELLOW="\[\033[33m\]"
RESET="\[\033[0m\]"

Saya ingin dapat menulis sesuatu seperti:

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '

Tapi ini tidak berhasil - kode warna muncul di prompt, seperti mereka melarikan diri. Warna berfungsi dengan benar jika saya menggunakan tanda kutip ganda sebagai gantinya PS1, tapi kemudian prompt hanya berubah ketika saya melakukannya source ~/.bashrc.

Saya sudah mencoba hal-hal lain saya pernah melihat orang melakukan - menggunakan printf, menggunakan tanda kutip tunggal untuk warna, menempatkan \[dan \]di PS1bukannya variabel warna, tapi sepertinya tidak ada pekerjaan.

Bagaimana saya bisa menggunakan variabel untuk kode warna?

Ismail Badawi
sumber
Bisakah Anda memberi kami milik Anda .bashrc?
cuonglm
@cuonglm Semua .bashrc Anda milik kami? Saya akan menunjukkan diri.
CivFan

Jawaban:

20

Solusinya adalah untuk mendapatkan shell untuk menggantikan variabel warna ketika mendefinisikan prompt, tetapi bukan fungsinya. Untuk melakukan ini, gunakan tanda kutip ganda seperti yang Anda coba semula, tetapi lepas dari perintah sehingga mereka tidak dievaluasi sampai prompt ditarik.

PS1="\u@\h:\w${YELLOW}\$(virtual_env)${GREEN}\$(git_branch)${RESET}$ "

Perhatikan \sebelum $()pada setiap perintah.

Jika kita menggema ini, kita melihat:

echo "$PS1"
\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ 

Seperti yang Anda lihat, variabel warna dapat diganti, tetapi bukan perintahnya.

Patrick
sumber
1
Ini tampaknya tidak berfungsi jika $ (git_branch) juga mencoba mencetak menggunakan $ {YELLOW} dll. Di bagian itu saja, Anda masih akan mendapatkan semua karakter [].
WB Reed
7

Masalahnya adalah bahwa variabel Anda GREENberisi string literal yang terdiri dari "braket backslash backslash nol tiga tiga" dan seterusnya. Itu tidak mengandung misalnya karakter pelarian ASCII seperti yang diperlukan untuk membuat terminal Anda berubah warna.

Anda dapat menempatkan karakter kontrol ke dalam GREEN(dan YELLOWdan RESET) secara manual, tetapi pilihan yang jauh lebih baik adalah menggunakan tputdi tempat pertama sehingga Anda tidak perlu melakukan hard code apa pun dan Anda akan mendukung semua jenis terminal.

GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
RESET="$(tput setaf 0)"

Alasan mengapa itu dunia ketika Anda menempatkan "backslash nol tiga tiga" dll ... langsung ke PS1adalah bahwa interpretasi urutan backslash tertentu adalah fitur bisikan bash (lihat bagian PROMPTING dalam manual. Substitusi ini terjadi sebelum ekspansi parameter, perintah substitusi, ekspansi aritmatika, dan penghapusan kutipan, jadi itu tidak diterapkan pada hasil semua operasi lainnya.

Celada
sumber
5
Saat melakukannya dengan cara ini, Anda perlu membungkus variabel warna di \[\]dalam $PS1. Sebagai contoh: PS1='\u@\h:\w\[${YELLOW}\]'. Jika Anda tidak melakukan ini, dan Anda berakhir dengan perintah panjang yang membungkus ke baris berikutnya, Anda akan menghadapi segala macam masalah. Shell menggunakan \[\]untuk menentukan karakter mana yang tidak dapat dicetak, sehingga tidak memasukkan mereka ke dalam perhitungan panjang prompt. Perlu ini sehingga dapat menarik garis dengan benar ketika melebihi lebar terminal.
Patrick
Saya tidak tahu tput, terima kasih. Saya akan menggunakan jawaban Patrick untuk saat ini tetapi saya akan mengunjungi ini lagi ketika saya mendapat kesempatan.
Ismail Badawi
2

Ubah cara Anda mengisi $ GREEN, $ YELLOW, dan $ RESET:

GREEN="$(echo -e "\033[32m")"
YELLOW="$(echo -e "\033[33m")"
RESET="$(echo -e "\033[0m")"

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '
Cyrus
sumber
1
Ini berlaku melakukan hal yang persis sama dengan jawaban Celada. Tapi Celada lebih portabel jika terminal menggunakan kode pelarian yang berbeda untuk pengaturan warna. Ini juga akan memiliki masalah yang sama dengan hal multi-line prompt.
Patrick
2
The \[…\]kebutuhan bit untuk tetap berada di prompt, Anda tidak dapat hal itu dalam variabel. Anda telah menghapusnya sama sekali, yang akan menyebabkan masalah tampilan (kursor tidak berada pada posisi di mana bash mengharapkannya).
Gilles 'SO- berhenti bersikap jahat'
Selain kekhawatiran @Patrick, gema -e juga tidak portabel.
helpermethodhod
1
Dengan non-portabilitas muncul lebih banyak fitur - tput setafjangan biarkan Anda memilih dari set warna "cahaya", seperti cyan cahaya. @ Cyrus menjawab, namun, tidak.
CivFan