Bagaimana suatu program memutuskan apakah akan berwarna atau tidak?

17

Ketika saya menjalankan perintah dari terminal yang mencetak keluaran berwarna (seperti lsatau gcc), keluaran berwarna dicetak. Dari pemahaman saya, proses ini sebenarnya menghasilkan kode pelarian ANSI , dan terminal memformat warna.

Namun, jika saya menjalankan perintah yang sama dengan proses lain (misalnya aplikasi C kustom) dan mengarahkan output ke output aplikasi sendiri, warna-warna ini tidak bertahan.

Bagaimana suatu program memutuskan apakah akan mengeluarkan teks dengan format warna atau tidak? Apakah ada beberapa variabel lingkungan?

Chris Smith
sumber

Jawaban:

25

Sebagian besar program semacam itu hanya mengeluarkan kode warna ke terminal secara default; mereka memeriksa untuk melihat apakah output mereka adalah TTY, menggunakan isatty(3). Biasanya ada opsi untuk mengesampingkan perilaku ini: menonaktifkan warna dalam semua kasus, atau mengaktifkan warna dalam semua kasus. Untuk GNU grepmisalnya, --color=nevermenonaktifkan warna dan --color=alwaysmengaktifkannya.

Dalam sebuah shell Anda dapat melakukan tes yang sama menggunakan -t testoperator: [ -t 1 ]hanya akan berhasil jika output standar adalah terminal.

Stephen Kitt
sumber
Apakah ada beberapa cara untuk mengelabui aplikasi yang dimulai bahwa prosesnya tty?
Chris Smith
4
Ditanyakan dan dijawab di unix.stackexchange.com/questions/249723 , chris13523. Ngomong-ngomong, komentar bukanlah tempat untuk pertanyaan lanjutan.
JdeBP
1
@ chris13524 lihat tautan JdeBP; Anda juga dapat memaksa program untuk mengeluarkan kode warna dalam banyak kasus (lihat jawaban saya yang diperbarui).
Stephen Kitt
13

Apakah ada beberapa variabel lingkungan?

Iya. Itu adalah TERMvariabel lingkungan. Ini karena ada beberapa hal yang digunakan sebagai bagian dari proses pengambilan keputusan.

Sulit untuk menggeneralisasi di sini, karena tidak semua program menyetujui satu alur keputusan tunggal. Sebenarnya GNU grep, yang disebutkan dalam jawaban M. Kitt, adalah contoh yang baik dari pencilan yang menggunakan proses keputusan yang agak tidak biasa dengan hasil yang tidak terduga. Secara umum, oleh karena itu:

  • Output standar harus berupa perangkat terminal, sebagaimana ditentukan oleh isatty().
  • Program harus dapat melihat catatan untuk tipe terminal dalam termcap / terminfo database.
  • Jadi karena itu harus ada tipe terminal untuk mencari. The TERMvariabel lingkungan harus ada dan nilainya harus sesuai catatan database.
  • Oleh karena itu harus ada database terminfo / termcap. Pada beberapa implementasi dari subsistem, lokasi database termcap dapat ditentukan menggunakan TERMCAPvariabel lingkungan. Jadi pada beberapa implementasi ada variabel lingkungan kedua .
  • Catatan termcap / terminfo harus menyatakan bahwa jenis terminal mendukung warna. Ada max_colorsbidang dalam terminfo. Ini tidak diatur untuk tipe terminal yang sebenarnya tidak memiliki kemampuan warna. Memang, ada konvensi terminfo bahwa untuk setiap jenis terminal colourable ada catatan lain dengan -matau -monoditambahkan ke nama yang tidak menyatakan kemampuan warna.
  • Catatan termcap / terminfo harus menyediakan cara bagi program untuk mengubah warna. Ada set_a_foregrounddan set_a_backgroundbidang dalam terminfo.

Ini sedikit lebih kompleks dari sekedar memeriksa isatty(). Hal ini semakin rumit dengan beberapa hal:

  • Beberapa aplikasi menambahkan opsi baris perintah atau flag konfigurasi yang mengesampingkan isatty()pemeriksaan, sehingga program selalu atau tidak pernah mengasumsikan bahwa ia memiliki terminal (colourable) sebagai outputnya. Sebagai contoh:
    • GNU lsmemiliki --coloropsi baris perintah.
    • BSD lsmelihat variabel lingkungan CLICOLOR(tidak adanya artinya tidak pernah ) dan CLICOLOR_FORCE(keberadaannya selalu berarti ), dan juga menggunakan -Gopsi baris perintah.
  • Beberapa aplikasi tidak menggunakan termcap / terminfo dan memiliki tanggapan bawaan untuk nilai TERM.
  • Tidak semua terminal menggunakan urutan SGR-ECMA-48 atau ISO 8613-6, yang sedikit dinamai "ANSI escape sequence", untuk mengubah warna. Mekanisme termcap / terminfo sebenarnya dirancang untuk melindungi aplikasi dari pengetahuan langsung dari urutan kontrol yang tepat. (Selain itu, ada argumen yang bisa diambil bahwa tidak ada yang menggunakan urutan ISO 8613-6 SGR, karena semua orang setuju pada bug menggunakan semi-kolon sebagai pembatas untuk urutan warna SGR RGB. Standar sebenarnya menentukan usus besar.)

Seperti disebutkan, GNU grepsebenarnya menunjukkan beberapa kompleksitas tambahan ini. Itu tidak berkonsultasi termcap / terminfo, hardware urutan kontrol untuk memancarkan, dan hardware respon TERMterhadap variabel lingkungan.

The Linux / Unix pelabuhan itu memiliki kode ini , yang memungkinkan colourization hanya ketika TERMvariabel lingkungan ada dan nilainya tidak sesuai dengan nama bawaan dumb:

int
should_colorize (batal)
{
  char const * t = getenv ("TERM");
  return t && strcmp (t, "dumb")! = 0;
}

Jadi bahkan jika Anda TERMyaitu xterm-mono, GNU grepakan memutuskan untuk warna memancarkan, meskipun program lain seperti vimtidak akan.

The Win32 pelabuhan itu memiliki kode ini , yang memungkinkan colourization baik ketika TERMvariabel lingkungan tidak ada atau ketika ada dan nilainya tidak sesuai dengan nama bawaan dumb:

int
should_colorize (batal)
{
  char const * t = getenv ("TERM");
  kembali! (t && strcmp (t, "dumb") == 0);
}

grepMasalah GNU dengan warna

grepPewarnaan GNU sebenarnya terkenal. Karena itu tidak benar-benar melakukan pekerjaan yang tepat untuk membangun keluaran terminal, tetapi lebih dari hanya mengacaukan dalam beberapa urutan kontrol bawaan pada berbagai titik dalam outputnya dengan harapan sia-sia bahwa itu cukup baik, itu sebenarnya menampilkan output yang salah dalam keadaan tertentu.

Keadaan ini adalah di mana ia harus mewarnai sesuatu yang berada di margin kanan terminal. Program yang melakukan keluaran terminal dengan benar harus memperhitungkan margin kanan otomatis. Selain kemungkinan kecil bahwa terminal mungkin tidak memilikinya (yaitu auto_right_marginbidang dalam terminfo), perilaku terminal yang memiliki margin kanan otomatis sering mengikuti DEC VT preseden dari pembungkus garis pending . GNU greptidak memperhitungkan ini, naif mengharapkan bungkus garis langsung , dan output berwarna salah.

Output berwarna bukanlah hal yang sederhana.

Bacaan lebih lanjut

JdeBP
sumber
2
Seperti yang saya pahami, OP bertanya tentang perubahan perilaku ketika output diarahkan; $TERMtidak menjelaskan itu. (Jawaban Anda menarik secara umum, tetapi saya tidak berpikir itu menjawab pertanyaan ...)
Stephen Kitt
sangat menarik. Saya menginginkan gambaran seperti ini tentang bagaimana program menemukan (atau sekadar "memutuskan") kemampuan terminal apa saja selama beberapa bulan sekarang. Ini juga memberikan wawasan mengapa sulit untuk menemukan gambaran seperti ini - karena setiap program tampaknya melakukannya sedikit berbeda.
the_velour_fog
Penjelasan tentang apa artinya bungkus garis yang ditangguhkan dan bungkus garis segera bersama dengan contoh yang menunjukkan perbedaan akan menyenangkan.
Mosvy
0

The unbufferperintah dari berharap paket de-pasangan output dari program pertama dan input ke program kedua.

Anda akan menggunakannya seperti ini:

unbuffer myshellscript.sh | grep value

Saya menggunakannya sepanjang waktu dengan ansible dan yg dibuat ctee naskah sehingga saya bisa melihat output warna pada terminal, sementara meninggalkan file log dengan normal (non-berwarna) output.

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log
bgStack15
sumber