Bagaimana cara memasukkan perintah dalam Bash's PS1 tanpa melanggar perhitungan panjang garis?

13

Tonin menunjukkan bug di prompt default saya . Contoh minimal:

  1. Setel PS1:

    PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " ")$ '

    Pada titik ini, prompt terlihat seperti ini:

    $ 
  2. Sekarang picu output kode keluar dengan menjalankan:

    false

    Sekarang prompt berisi kode keluar berwarna merah di awal baris:

    1 $ 
  3. Tekan Ctrl- r.
  4. Ketik "false". Sekarang prompt hanya berisi pencarian:

    (reverse-i-search)`false': false
  5. Tekan Enter.

Sejarah terminal yang dihasilkan sekarang berisi yang berikut:

1 $ch)`false': false

Output yang diharapkan:

1 $ false

Artinya, tampaknya hasil pencarian riwayat dicampur dengan prompt dan menyembunyikan perintah aktual yang dijalankan.

Saya mencoba mengatasinya dengan menggunakanPROMPT_COMMAND :

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " "
}
set_bash_prompt() {
    PS1='$(set_exit_code)$ ' # Double quotes give the same result
}
PROMPT_COMMAND=set_bash_prompt

Ini sepertinya tidak berfungsi - garis terlihat persis sama seperti sebelumnya setelah mencari dan menjalankan.

Bagaimana saya bisa memperbaikinya?

l0b0
sumber
1
Ini tampaknya merupakan kelanjutan dari unix.stackexchange.com/a/71012
manatwork

Jawaban:

8

Saya menemukan jawabannya di askubuntu.com . @qeirha menyebutkan bahwa Anda harus memberi tahu bash bahwa urutan karakter tidak boleh dihitung dalam panjang prompt, dan Anda melakukannya dengan menyertakannya \[ \]. Berdasarkan contoh yang diberikan, berikut adalah salah satu solusinya:

red=$(tput setaf 1)

reset=$(tput sgr0)

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$red\] $exit_code \[$reset\] " ")$ '
Timothy Martin
sumber
Tidak perlu pergi ke Tanya Ubuntu untuk itu. Kami sudah memiliki jawaban yang cukup untuk pertanyaan ini di sini juga.
manatwork
Terima kasih atas saran @manatwork! Saya ingin memberikan penghargaan yang layak untuk penjelasan dan memberikan referensi sebagai rasa hormat.
Timothy Martin
Memberi kredit bukanlah masalah. Tetapi ketika berbicara tentang masalah: backslash unescaped digunakan untuk menghilang dari Markdown, jadi dataran Anda [menjadi [di pos Anda, sehingga kode yang ditampilkan tidak berfungsi dengan menyalin-menempelkannya ke terminal. Ini dapat dihindari dengan menggunakan kode sebaris atau markup blok kode. ( Bagaimana cara memformat posting saya menggunakan Markdown atau HTML? )
manatwork
1
Doh! Saya sudah memperbaiki masalah yang sama untuk PS1kode lain , mengapa saya tidak melihatnya?
l0b0
1
PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$(tput setaf 1)\] $exit_code \[$(tput sgr0)\] " ")$ '

(Maaf, tidak ada penjelasan di sini. Lihat Bagaimana menyesuaikan PS1 dengan benar? Atau pertanyaan lain tentang masalah perhitungan panjang cepat dan \[... \])

manatwork
sumber
Untuk pertanyaan kedua @ l0b0, saya akan menambahkan bahwa menggunakan PS1 dan \[...\]berfungsi dengan baik selama Anda dapat menempatkan semua kode yang Anda ingin hasilkan dalam satu string. Namun, jika Anda ingin membagi kode menjadi fungsi-fungsi kecil, Anda sampai pada titik di mana Anda tidak dapat menempatkan tanda kurung mulai dan berakhir di string / fungsi yang sama. Dan itu melanggar garis bungkus. Kecuali jika Anda menggunakan PROMPT_COMMANDuntuk menghitung ulang Anda PS1di setiap prompt.
Tonin
1

Memperluas jawaban @manatwork tetapi menjaga agar kode Anda tidak membelah PS1komputasi dalam fungsi yang berbeda, Anda dapat menulis prompt Anda dengan cara berikut:

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf "\[$(tput setaf 1)\] $exit_code \[$(tput sgr0)\] "
}
set_bash_prompt() {
    PS1="$(set_exit_code)$ " # with double quotes!
}
PROMPT_COMMAND=set_bash_prompt

Kutipan ganda wajib saat mengatur PS1dan ketika menggunakan printfdalam fungsi.

Tonin
sumber
Untuk referensi di masa mendatang, gunakan fungsi bash di Anda .bashrc- jangan masukkan kode dalam file terpisah dan panggil itu.
starbeamrainbowlabs