Có thể sử dụng mã thoát màu ANSI trong Bash ở đây - tài liệu không?


7

Tôi đang in một tin nhắn trong tập lệnh Bash và tôi muốn tô màu một phần của nó; ví dụ,

#!/bin/bash

normal='\e[0m'
yellow='\e[33m'
cat <<- EOF
    ${yellow}Warning:${normal} This script repo is currently located in:
    [ more messages... ]
EOF

Nhưng khi tôi chạy trong thiết bị đầu cuối ( tmuxbên trong gnome-terminal), các ký tự thoát ANSI chỉ được in \dưới dạng; ví dụ,

\e[33mWarning\e[0m This scr....

Nếu tôi di chuyển phần tôi muốn chuyển sang một printflệnh bên ngoài tài liệu ở đây, nó sẽ hoạt động. Ví dụ, điều này hoạt động:

printf "${yellow}Warning:${normal}"
cat <<- EOF
    This script repo is currently located in:
    [ more messages... ]
EOF

Từ man bash- Tại đây Tài liệu:

Không có mở rộng tham số và biến, thay thế lệnh, mở rộng số học hoặc mở rộng tên đường dẫn được thực hiện trên word . Nếu bất kỳ ký tự nào trong từ được trích dẫn, dấu phân cách là kết quả của việc loại bỏ trích dẫn trên từ và các dòng trong tài liệu ở đây không được mở rộng. Nếu từ không được trích dẫn, tất cả các dòng của tài liệu ở đây phải chịu sự mở rộng tham số, thay thế lệnh và mở rộng số học. Trong trường hợp sau, chuỗi ký tự \ <xuống dòng> bị bỏ qua, và \phải được sử dụng để trích dẫn các nhân vật \, $`.

Tôi không thể tìm hiểu làm thế nào điều này sẽ ảnh hưởng đến mã thoát ANSI. Có thể sử dụng mã thoát ANSI trong tài liệu Bash ở đây catkhông?


Tôi không nghĩ rằng điều này có liên quan đến các tài liệu ở đây. Biến của bạn chứa chuỗi ký tự \e[33mvà được thay thế bình thường trong cả hai trường hợp. Nếu bạn có một số lý do để nghĩ rằng nó bị giới hạn trong heredocs hoặc một chút mã thực sự thể hiện hành vi mà bạn quan tâm, vui lòng chỉnh sửa nó.
Michael Homer

2
Hoặc yellow=$'\e[33m'hoặc yellow=$(printf '\e[33m')(như bạn đã làm) sẽ đưa ký tự thoát vào chuỗi trực tiếp để kiểm tra.
Michael Homer

1
@MichaelHomer Vậy về cơ bản chuỗi '\e[33m'này là vô nghĩa đối với một thiết bị đầu cuối? nó chỉ có ý nghĩa đối với các lệnh như echo -ehoặc printf- sau đó tạo ra mã "thực" được gửi đến thiết bị đầu cuối?
the_velour_fog

Đúng.
Michael Homer

Câu trả lời:


25

Trong kịch bản của bạn, những bài tập này

normal='\e[0m'
yellow='\e[33m'

đặt các ký tự đó theo nghĩa đen vào các biến, nghĩa là \e[0m, thay vì chuỗi thoát. Bạn có thể tạo một ký tự thoát bằng cách sử dụng printf(hoặc một số phiên bản echo), ví dụ:

normal=$(printf '\033[0m')
yellow=$(printf '\033[33m')

nhưng bạn sẽ làm tốt hơn nhiều để sử dụng tput, vì điều này sẽ hoạt động cho bất kỳ thiết bị đầu cuối được thiết lập chính xác:

normal=$(tput sgr0)
yellow=$(tput setaf 3)

Nhìn vào ví dụ của bạn, có vẻ như phiên bản của printfbạn đang sử dụng các đối xử \enhư là ký tự thoát (có thể hoạt động trên hệ thống của bạn, nhưng thường không thể di chuyển sang các hệ thống khác). Để thấy điều này, hãy thử

yellow='\e[33m'
printf 'Yellow:%s\n' $yellow

và bạn sẽ thấy các nhân vật theo nghĩa đen :

Yellow:\e[33m

thay vì trình tự thoát. Đặt những người trong printfđịnh dạng nói printfđể giải thích chúng (nếu có thể).

Đọc thêm:


Tôi không hiểu ý của bạn bằng cách đặt các ký tự đó theo nghĩa đen vào các biến - đó không phải là điều bạn muốn sao? tức là các biến chỉ lưu trữ các giá trị cho đến khi các biến được nội suy vào chuỗi?
the_velour_fog

Định dạng này dường như không hoạt động đáng tin cậy (không yellowhoạt động, nhưng normalđã làm). nhưng normal=$(tput sgr0) định dạng đang hoạt động hoàn hảo!
the_velour_fog

1
ah ok, do đó, printf 'Yellow:%s\n' $yellow sản xuất các ký tự theo nghĩa đen bởi vì printfđã không được Yellowđối xử "đặc biệt". Vì vậy, lý do điều này hoạt động printf "%s" "$(tput setaf 3)foo$(tput sgr0)"là bởi vì thông số đang tạo ra các chuỗi thoát mà thiết bị đầu cuối có thể nhận ra trực tiếp, thật tuyệt khi biết cảm ơn!
the_velour_fog

Cũng red=$'\e[31m'trong ksh93, bash, zsh, mksh, FreeBSD sh và sớm POSIX.
Stéphane Chazelas

2

Nhiệm vụ này không đặt các ký tự thoát trong biến:

normal='\e[0m'                  yellow='\e[33m'

Để làm như vậy, bạn cần echo -e printfhoặc $'...'(trong bash).

Vì bạn đang sử dụng bash, bạn cũng có thể sử dụng điều này:

normal=$'\e[0m'                 yellow=$'\e[33m'

Xin lưu ý $trước chuỗi '\e[0m'.

Tuy nhiên, cách di động để có được các ký tự thoát là printf, như sau:

normal="$(printf '\033[0m')"    yellow="$(printf '\033[33m')"

Giá trị bát phân (033) của ký tự thoát là hợp lệ trong tất cả các vỏ POSIX.


Lưu ý rằng $'\e[0msẽ được trong vấn đề lớn tiếp theo của đặc tả POSIX và đã được hỗ trợ trong ksh93(nơi nó xuất phát từ), bash, zsh, mkshvà FreeBSD shít nhất.
Stéphane Chazelas

Lưu ý rằng echo -eđầu ra "-e\n" trong triển khai tiếng vang tuân thủ POSIX. echo '\033'xuất ra một ký tự ESC có echos phù hợp với Unix trên các hệ thống dựa trên ASCII.
Stéphane Chazelas

@ StéphaneChazelas Tôi có ấn tượng rằng một vị trí hợp lý printflà một giải pháp tốt. Và rằng sử dụng printf là một cách để tránh trình bày, thảo luận và cuối cùng từ chối việc sử dụng sai sót trong nhiều cách echo. Điều gì làm cho nó hữu ích để chỉ vào lệnh echotrong câu trả lời này?
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.