Thoát các ký tự không in trong hàm cho dấu nhắc Bash


22

Trong Bash Prompt (biến PS1), tôi đang gọi một hàm để có khả năng thêm văn bản vào dấu nhắc: export PS1="\u@\h \$(my_function) \$ "

Tuy nhiên, hàm trong lời nhắc chứa mã màu ANSI thay đổi dựa trên đầu ra của hàm (đôi khi là màu đỏ, đôi khi là màu xanh lá cây). Việc thêm " \[" vào biến PS1 sẽ thoát các mã đó thành không in, nhưng nếu tôi thực hiện một echochức năng, " \[" sẽ được in theo nghĩa đen trong lời nhắc.

Làm cách nào tôi có thể thoát các mã màu ANSI này từ bên trong một hàm để sử dụng trong dấu nhắc bash?

Câu trả lời:


34

Các readline thư viện chấp nhận \001\002(ASCII SOH và STX ) như delimiters văn bản không thể in được. Chúng cũng hoạt động trong bất kỳ ứng dụng nào sử dụng readline .

Từ lib/readline/display.c:243trong mã nguồn 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'. */

Các bash cụ thể \[\]được trên thực tế dịch sang \001\002y.tab.c:7640.


Lưu ý: Nếu bạn sử dụng bash 's printfhoặc echo -e, và nếu văn bản của bạn có \001hoặc \002ngay trước khi một con số, bạn sẽ đạt mức bash lỗi gây ra nó để ăn một chữ số quá nhiều khi xử lý bát phân thoát - có nghĩa là, \00142sẽ được hiểu là bát phân 014 (tiếp theo là ASCII "2"), thay vì bát phân chính xác 01 (tiếp theo là ASCII "42"). Vì lý do này, sử dụng các phiên bản thập lục phân \x01\x02thay vào đó.


Đó là nó! echo -e "\001\e[31m\002RED"hoạt động như mong đợi. Cảm ơn!
Nửa đêm

Xin lỗi để hồi sinh một câu trả lời, nhưng những gì tương đương trên dash / ash / sh?
Hosh Sadiq

@Hosh Nếu họ sử dụng readline, \001\002sẽ hoạt động. Nếu không thì tôi không chắc. Ví dụ, Dash chắc chắn không sử dụng readline .
wjandrea

1

Đây là một câu trả lời đầy đủ tốt đẹp. Tôi đã phải đào bới nhiều hơn nữa để tìm ra nơi \ 001, v.v. Hi vọng điêu nay co ich.

# 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 "

Cách tôi thiết lập ở đây, dấu ngoặc đơn của git chỉ xuất hiện nếu bạn ở trong nhánh git, nếu không thì trống.


0

Dựa trên câu trả lời của grawity , phần sau đây sẽ kèm theo các chuỗi điều khiển ANSI trong ASCII SOH( ^A) và STX( ^B) tương đương \[\]tương ứng:

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'
}

Sử dụng nó như:

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

Hoặc là:

$ readline_ANSI_escape "$string"

Là một phần thưởng, chạy chức năng nhiều lần sẽ không thoát lại các mã kiểm soát đã thoát.


-2

Nếu bạn muốn sử dụng chúng trong lời nhắc, thì bạn cần phải làm \[. Nhưng nếu bạn muốn sử dụng nó trong tiếng vang, bạn phải sử dụng \033[.


Hmmm ... Thêm \ 033 [trước lệnh ANSI ("\ e [31m") và \ 033] sau khi nó dường như làm cho ký tự in tiếp theo trong lời nhắc không được in.
Nửa đêm

1
Bạn không muốn làm \ 033] sau nó. \ 033 [31m bắt đầu màu, sau đó bạn cần đặt lại với \ 033 [0m
Wuffers
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.