Làm thế nào để bao gồm các lệnh trong PS1 của Bash mà không phá vỡ tính toán độ dài dòng?


13

Tonin đã chỉ ra một lỗi trong lời nhắc mặc định của tôi . Ví dụ tối thiểu:

  1. Đặt PS1:

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

    Tại thời điểm này, lời nhắc trông như thế này:

    $ 
  2. Bây giờ kích hoạt đầu ra mã thoát bằng cách chạy:

    false

    Bây giờ lời nhắc chứa mã thoát màu đỏ ở đầu dòng:

    1 $ 
  3. Nhấn Ctrl- r.
  4. Nhập "sai". Bây giờ lời nhắc chỉ chứa tìm kiếm:

    (reverse-i-search)`false': false
  5. Nhấn Enter.

Lịch sử thiết bị đầu cuối kết quả hiện có chứa như sau:

1 $ch)`false': false

Sản lượng dự kiến:

1 $ false

Đó là, có vẻ như đầu ra tìm kiếm lịch sử được trộn lẫn với dấu nhắc và ẩn lệnh thực tế đã được chạy.

Tôi đã thử làm việc xung quanh điều này bằng cách sử dụngPROMPT_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

Điều này dường như không hoạt động - dòng trông giống hệt như trước khi tìm kiếm và chạy.

Làm thế nào tôi có thể sửa lỗi này?


1
Đây dường như là sự tiếp nối của unix.stackexchange.com/a/71012
manatwork 19/12/13

Câu trả lời:


8

Tôi tìm thấy câu trả lời trên Askubfox.com . @qeirha đã đề cập rằng bạn phải nói với bash rằng chuỗi ký tự không được tính vào độ dài của dấu nhắc và bạn làm điều đó bằng cách đặt nó vào \[ \]. Dựa trên ví dụ được cung cấp, đây là một giải pháp:

red=$(tput setaf 1)

reset=$(tput sgr0)

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$red\] $exit_code \[$reset\] " ")$ '

Không cần phải đi hỏi Ubuntu cho nó. Chúng tôi đã có đủ câu trả lời cho câu hỏi này ở đây quá.
manatwork

Cảm ơn bạn đã cho lời khuyên @manatwork! Tôi muốn cung cấp tín dụng thích hợp cho lời giải thích và cung cấp tài liệu tham khảo như một phép lịch sự.
Timothy Martin

Cung cấp tín dụng không phải là một vấn đề. Nhưng trong khi nói về vấn đề: dấu gạch chéo ngược không được sử dụng để biến mất khỏi Markdown, do đó, đơn giản \ [trở thành [trong bài đăng của bạn, do đó mã được hiển thị không hoạt động bằng cách sao chép nó vào thiết bị đầu cuối. Điều này có thể tránh được bằng cách sử dụng mã nội tuyến hoặc đánh dấu khối mã. ( Làm cách nào để định dạng bài đăng của tôi bằng Markdown hoặc HTML? )
manatwork 19/12/13

1
Ôi! Tôi đã sửa vấn đề tương tự cho PS1mã khác , tại sao tôi không thấy mã đó?
l0b0

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

(Xin lỗi, không có lời giải thích nào ở đây. Xem Cách tùy chỉnh PS1 đúng cách? Hoặc bất kỳ câu hỏi nào khác về các vấn đề tính toán độ dài nhắc nhở và\[ ... \])


Đối với câu hỏi thứ hai @ l0b0, tôi sẽ thêm rằng sử dụng PS1 và \[...\]hoạt động tốt miễn là bạn có thể đặt tất cả mã bạn muốn tạo lời nhắc của mình trong một chuỗi. Tuy nhiên, nếu bạn muốn chia mã của mình thành các hàm nhỏ, bạn đến một điểm mà bạn không thể đặt dấu ngoặc bắt đầu và kết thúc trong cùng một chuỗi / hàm. Và phá vỡ bọc dòng. Trừ khi bạn sử dụng PROMPT_COMMANDđể tính toán lại PS1tại mỗi dấu nhắc.
Tonin

1

Mở rộng câu trả lời @manatwork nhưng giữ cho mã của bạn phân tách PS1tính toán trong các hàm khác nhau, bạn có thể viết lời nhắc của mình theo cách sau:

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

Dấu ngoặc kép là bắt buộc cả khi cài đặt PS1và khi sử dụng printftrong chức năng.


Để tham khảo trong tương lai, hãy sử dụng hàm bash trong .bashrc- đừng đặt mã vào một tệp riêng và gọi nó.
starbeamrainbowlabs
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.