Keluar dari karakter yang tidak dicetak dalam fungsi untuk Bash prompt

22

Dalam Bash Prompt (variabel PS1), saya memanggil fungsi untuk berpotensi menambahkan teks ke prompt: export PS1="\u@\h \$(my_function) \$ "

Namun, fungsi di prompt berisi kode warna ANSI yang berubah berdasarkan output fungsi (kadang-kadang merah, kadang-kadang hijau). Menambahkan " \[" ke variabel PS1 harus lolos dari kode-kode itu sebagai non-pencetakan, tetapi jika saya melakukan suatu echofungsi, " \[" akan dicetak secara harfiah di prompt.

Bagaimana saya bisa lepas kode warna ANSI ini dari dalam fungsi untuk digunakan dalam bash prompt?

MidnightLightning
sumber

Jawaban:

34

The readline perpustakaan menerima \001dan \002(ASCII SOH dan STX ) sebagai pembatas teks non-printable. Ini juga berfungsi di aplikasi apa pun yang menggunakan readline .

Dari lib/readline/display.c:243dalam kode sumber bash :

243 /* Current implementation:
244         \001 (^A) start non-visible characters
245         \002 (^B) end non-visible characters
246    all characters except \001 and \002 (following a \001) are copied to
247    the returned string; all characters except those between \001 and
248    \002 are assumed to be `visible'. */

The pesta -specific \[dan \]yang sebenarnya diterjemahkan ke \001dan \002di y.tab.c:7640.


Catatan: Jika Anda menggunakan bash 's printfatau echo -e, dan jika teks Anda memiliki \001atau \002segera sebelum angka, Anda akan menekan bug bash yang menyebabkannya memakan satu digit terlalu banyak saat memproses lolos oktal - yaitu, \00142akan ditafsirkan sebagai oktal 014 (diikuti oleh ASCII "2"), bukannya oktal yang benar 01 (diikuti oleh ASCII "42"). Untuk alasan ini, gunakan versi heksadesimal \x01dan \x02sebagai gantinya.

grawity
sumber
Itu berhasil! echo -e "\001\e[31m\002RED"bekerja seperti yang diharapkan. Terima kasih!
MidnightLightning
Maaf untuk membangkitkan kembali jawaban, tapi apa yang setara di dash / ash / sh?
Hosh Sadiq
@ Wah Jika mereka menggunakan readline, \001dan \002akan bekerja. Kalau tidak, saya tidak yakin. Dash misalnya tidak menggunakan readline .
wjandrea
1

Inilah jawaban lengkap yang bagus. Saya harus melakukan lebih banyak penggalian untuk mencari tahu ke mana \ 001 dll harus pergi. Semoga ini membantu.

# Color prompt for git
reset=$(tput sgr0)
boldgreen=$(tput setaf 2)$(tput bold)
cyan=$(tput sgr0)$(tput setaf 6)
boldred=$(tput setaf 1)$(tput bold)
boldwhite=$(tput setaf 7)$(tput bold)
boldyellow=$(tput setaf 3)$(tput bold)

PARENCLR=$'\001\e[0;36m\002'
BRANCHCLR=$'\001\e[1;33m\002'

alias branchname="git branch 2>/dev/null | grep '*' | sed 's/* \(.*\)/ ${PARENCLR}(${BRANCHCLR}\1${PARENCLR}\)/'"

GIT_STATUS='$(branchname)'

PROMPT_CHAR="\$"
PS1="\[$boldgreen\]\u\[$cyan\]::\[$boldred\]\h \[$cyan\]{\[$boldwhite\].../\W\[$cyan\]}\[$reset\]$GIT_STATUS\[$reset\]$PROMPT_CHAR "

Cara saya mengaturnya di sini, kurung cabang git hanya muncul jika Anda berada di cabang git, jika tidak maka kosong.

Dan L
sumber
0

Berdasarkan jawaban grawity , berikut ini akan menyertakan urutan kontrol ANSI di ASCII SOH( ^A) dan STX( ^B) yang setara dengan \[dan \]masing - masing:

function readline_ANSI_escape() {
  if [[ $# -ge 1 ]]; then
    echo "$*"
  else
    cat  # Read string from STDIN
  fi | \
  perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}

Gunakan seperti:

$ echo $'\e[0;1;31mRED' | readline_ANSI_escape

Atau:

$ readline_ANSI_escape "$string"

Sebagai bonus, menjalankan fungsi beberapa kali tidak akan keluar lagi dari kode kontrol yang sudah lolos.

Tom Hale
sumber
-2

Jika Anda ingin menggunakannya dalam prompt, maka Anda perlu melakukan itu \[. Tetapi jika Anda ingin menggunakannya dalam gema, Anda harus menggunakannya \033[.

Wuffers
sumber
Hmmm ... Menambahkan \ 033 [sebelum perintah ANSI ("\ e [31m") dan \ 033] setelah itu tampaknya membuat karakter yang dicetak berikutnya dalam prompt tidak dicetak.
MidnightLightning
1
Anda tidak ingin melakukan \ 033] setelah itu. \ 033 [31m memulai warna, setelah itu Anda harus mengaturnya kembali dengan \ 033 [0m
Wuffers