Làm thế nào để một chương trình quyết định có hay không có đầu ra màu?


17

Khi tôi thực thi một lệnh từ thiết bị đầu cuối in đầu ra màu (như lshoặc gcc), đầu ra màu được in. Theo hiểu biết của tôi, quá trình này thực sự xuất ra các mã thoát ANSI và thiết bị đầu cuối định dạng màu.

Tuy nhiên, nếu tôi thực hiện cùng một lệnh bởi một quy trình khác (giả sử ứng dụng C tùy chỉnh) và chuyển hướng đầu ra sang đầu ra của chính ứng dụng, các màu này không tồn tại.

Làm thế nào để một chương trình quyết định có hay không xuất văn bản với định dạng màu? Có một số biến môi trường?

Câu trả lời:


25

Hầu hết các chương trình như vậy chỉ xuất mã màu cho thiết bị đầu cuối theo mặc định; họ kiểm tra xem đầu ra của họ có phải là TTY không, sử dụng isatty(3). Thường có các tùy chọn để ghi đè hành vi này: tắt màu trong mọi trường hợp hoặc bật màu trong mọi trường hợp. Ví grepdụ, đối với GNU , --color=nevervô hiệu hóa màu sắc và --color=alwayscho phép chúng.

Trong một trình bao, bạn có thể thực hiện kiểm tra tương tự bằng cách sử dụng -t testtoán tử: [ -t 1 ]sẽ chỉ thành công nếu đầu ra tiêu chuẩn là một thiết bị đầu cuối.


Có một số cách để lừa ứng dụng đã bắt đầu rằng quá trình này là một tty?
Chris Smith

4
Đã hỏi và trả lời tại unix.stackexchange.com/questions/249723 rồi, chris13523. Nhân tiện, bình luận không phải là nơi dành cho các câu hỏi tiếp theo.
JdeBP

1
@ chris13524 xem liên kết của JdeBP; bạn cũng có thể buộc các chương trình xuất mã màu trong nhiều trường hợp (xem câu trả lời được cập nhật của tôi).
Stephen Kitt

13

Có một số biến môi trường?

Đúng. Đây là TERMbiến môi trường. Điều này là do có một số điều được sử dụng như một phần của quá trình quyết định.

Thật khó để khái quát ở đây, bởi vì không phải tất cả các chương trình đều đồng ý về một sơ đồ quyết định duy nhất. Trong thực tế GNU grep, được đề cập trong câu trả lời của M. Kitt, là một ví dụ điển hình về một ngoại lệ sử dụng quy trình quyết định hơi bất thường với kết quả không mong muốn. Về mặt rất chung chung, do đó:

  • Đầu ra tiêu chuẩn phải là một thiết bị đầu cuối, như được xác định bởi isatty().
  • Chương trình phải có khả năng tra cứu bản ghi cho loại thiết bị đầu cuối trong cơ sở dữ liệu termcap / terminfo.
  • Vì vậy, phải một loại thiết bị đầu cuối để tìm kiếm. Biến TERMmôi trường phải tồn tại và giá trị của nó phải khớp với bản ghi cơ sở dữ liệu.
  • Do đó phải có một cơ sở dữ liệu terminfo / termcap. Trên một số triển khai của hệ thống con, vị trí của cơ sở dữ liệu termcap có thể được chỉ định bằng cách sử dụng TERMCAPbiến môi trường. Vì vậy, trên một số triển khai có một biến môi trường thứ hai .
  • Bản ghi termcap / terminfo phải nói rằng loại thiết bị đầu cuối hỗ trợ màu sắc. Có một max_colorslĩnh vực trong terminfo. Nó không được đặt cho các loại thiết bị đầu cuối không thực sự có khả năng màu. Thật vậy, có một quy ước terminfo rằng đối với mỗi loại thiết bị đầu cuối có thể tách rời, có một bản ghi khác có -mhoặc -monogắn vào tên không có khả năng màu.
  • Bản ghi termcap / terminfo phải cung cấp cách để chương trình thay đổi màu sắc. Có set_a_foregroundset_a_backgroundcác lĩnh vực trong terminfo.

Nó phức tạp hơn một chút so với chỉ kiểm tra isatty(). Nó được làm thêm phức tạp bởi một vài điều:

  • Một số ứng dụng thêm tùy chọn dòng lệnh hoặc cờ cấu hình ghi đè isatty()kiểm tra, để chương trình luôn luôn hoặc không bao giờ giả định rằng nó có thiết bị đầu cuối (có thể chia sẻ) làm đầu ra. Ví dụ như:
    • GNU ls--colortùy chọn dòng lệnh.
    • BSD lsxem xét các biến môi trường CLICOLOR(nghĩa là không có nghĩa là không bao giờ ) và CLICOLOR_FORCE( luôn luôn có nghĩa là sự hiện diện của nó ) và cũng sử dụng -Gtùy chọn dòng lệnh.
  • Một số ứng dụng không sử dụng termcap / terminfo và có các phản hồi mong muốn về giá trị của TERM.
  • Không phải tất cả các thiết bị đầu cuối đều sử dụng trình tự ECMA-48 hoặc ISO 8613-6 SGR, được đặt tên hơi sai là "trình tự thoát ANSI", để thay đổi màu sắc. Cơ chế termcap / terminfo trên thực tế được thiết kế để cách ly các ứng dụng khỏi kiến ​​thức trực tiếp về các chuỗi điều khiển chính xác. (Hơn nữa, có một lập luận cho rằng không ai sử dụng trình tự ISO 8613-6 SGR, bởi vì mọi người đều đồng ý về lỗi sử dụng dấu chấm phẩy làm dấu phân cách cho chuỗi SGR màu RGB. Tiêu chuẩn thực sự chỉ định dấu hai chấm.)

Như đã đề cập, GNU grepthực sự thể hiện một số trong những phức tạp bổ sung này. Nó không tham khảo termcap / terminfo, cung cấp các chuỗi điều khiển để phát ra và tạo ra phản ứng với TERMbiến môi trường.

Cổng Linux / Unix của nó có mã này , cho phép chỉ thông báo khi TERMbiến môi trường tồn tại và giá trị của nó không khớp với tên cứng dumb:

int
nên_colorize (void)
{
  char const * t = getenv ("HẠN");
  trả về t && strcmp (t, "câm")! = 0;
}

Vì vậy, ngay cả khi TERMlà của bạn xterm-mono, GNU grepsẽ quyết định phát ra màu sắc, mặc dù các chương trình khác như vimsẽ không.

Cổng Win32 của nó có mã này , cho phép thông báo khi TERMbiến môi trường không tồn tại hoặc khi nó tồn tại và giá trị của nó không khớp với tên cứng dumb:

int
nên_colorize (void)
{
  char const * t = getenv ("HẠN");
  trở về ! (t && strcmp (t, "câm") == 0);
}

Các grepvấn đề về màu sắc của GNU

Sự thông minh của GNU grepthực sự khét tiếng. Bởi vì nó không thực sự làm tốt công việc xây dựng đầu ra thiết bị đầu cuối, mà chỉ thổi vào một vài chuỗi điều khiển cứng ở các điểm khác nhau trong đầu ra với hy vọng là đủ tốt, nó thực sự hiển thị đầu ra không chính xác trong một số trường hợp nhất định.

Những trường hợp này là nơi nó phải ghi lại một cái gì đó ở rìa bên phải của thiết bị đầu cuối. Các chương trình làm đầu ra thiết bị đầu cuối đúng cách phải tính đến lề phải tự động. Ngoài khả năng nhỏ là thiết bị đầu cuối có thể không có chúng (viz auto_right_margintrường trong terminfo), hành vi của các thiết bị đầu cuối có lề phải tự động thường tuân theo tiền lệ DEC VT của gói chờ xử lý . GNU grepkhông giải thích cho điều này, hoàn toàn mong đợi việc bọc dòng ngay lập tức và đầu ra màu của nó bị sai.

Đầu ra màu không phải là một điều đơn giản.

đọc thêm


2
Theo tôi hiểu, OP đang hỏi về sự thay đổi hành vi khi đầu ra được chuyển hướng; $TERMkhông giải thích điều đó. (Câu trả lời của bạn nói chung rất thú vị, nhưng tôi không nghĩ nó giải quyết được câu hỏi ...)
Stephen Kitt

rất thú vị. Tôi đã muốn có một cái nhìn tổng quan như thế này về cách các chương trình khám phá (hoặc đơn giản là "quyết định") khả năng của thiết bị đầu cuối trong vài tháng nay. Điều này cũng cung cấp một cái nhìn sâu sắc tại sao rất khó để tìm thấy một cái nhìn tổng quan như thế này - bởi vì mỗi chương trình dường như làm điều đó hơi khác nhau.
the_velour_fog

Một lời giải thích về việc bọc dòng chờ xử lýgói dòng ngay lập tức có nghĩa là gì với một ví dụ chứng minh sự khác biệt sẽ là tốt đẹp.
mosvy

0

Các unbufferlệnh từ mong đợi gói de-cặp vợ chồng đầu ra từ chương trình đầu tiên và đầu vào cho chương trình thứ hai.

Bạn sẽ sử dụng nó như thế này:

unbuffer myshellscript.sh | grep value

Tôi sử dụng nó mọi lúc với ansible và homebrewed ctee kịch bản để tôi có thể nhìn thấy đầu ra màu sắc trên thiết bị đầu cuối, trong khi để lại các log file với bình thường đầu ra (không colorized).

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log
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.