โปรแกรมจะตัดสินใจได้อย่างไรว่าจะให้สีออกมาหรือไม่?


17

เมื่อฉันรันคำสั่งจากเทอร์มินัลที่พิมพ์เอาต์พุตสี (เช่นlsหรือgcc) เอาต์พุตสีจะถูกพิมพ์ จากความเข้าใจของฉันกระบวนการกำลังส่งออกรหัสหลบหนี ANSIและเทอร์มินัลจะจัดรูปแบบสี

อย่างไรก็ตามถ้าฉันรันคำสั่งเดียวกันโดยกระบวนการอื่น (พูดแอปพลิเคชัน C แบบกำหนดเอง) และเปลี่ยนเส้นทางเอาต์พุตไปยังเอาต์พุตของแอปพลิเคชันสีเหล่านี้จะไม่คงอยู่

โปรแกรมตัดสินใจอย่างไรว่าจะแสดงข้อความที่มีรูปแบบสีหรือไม่ มีตัวแปรสภาพแวดล้อมบ้างไหม?

คำตอบ:


25

โปรแกรมส่วนใหญ่ดังกล่าวจะส่งรหัสสีไปยังเทอร์มินัลโดยค่าเริ่มต้นเท่านั้น พวกเขาตรวจสอบเพื่อดูว่าการส่งออกของพวกเขาคือ TTY isatty(3)โดยใช้ โดยทั่วไปจะมีตัวเลือกเพื่อแทนที่ลักษณะการทำงานนี้: ปิดใช้งานสีในทุกกรณีหรือเปิดใช้งานสีในทุกกรณี สำหรับ GNU grepเช่น--color=neverปิดการใช้งานสีและ--color=alwaysเปิดใช้งานพวกเขา

ในเชลล์คุณสามารถทำการทดสอบเดียวกันโดยใช้-t testโอเปอเรเตอร์: [ -t 1 ]จะทำได้ก็ต่อเมื่อเอาต์พุตมาตรฐานคือเทอร์มินัล


มีวิธีการหลอกลวงแอปพลิเคชั่นที่เริ่มต้นแล้วหรือไม่
Chris Smith

4
ถามและตอบที่unix.stackexchange.com/questions/249723แล้ว chris13523 ความคิดเห็นไม่ใช่สถานที่สำหรับคำถามที่ตามมา
JdeBP

1
@ chris13524 ดูลิงก์ของ JdeBP; คุณสามารถบังคับให้โปรแกรมแสดงผลรหัสสีในหลาย ๆ กรณี (ดูคำตอบที่อัพเดตของฉัน)
Stephen Kitt

13

มีตัวแปรสภาพแวดล้อมบ้างไหม?

ใช่. มันเป็นTERMตัวแปรสภาพแวดล้อม เนื่องจากมีหลายสิ่งที่ใช้เป็นส่วนหนึ่งของกระบวนการตัดสินใจ

เป็นการยากที่จะพูดคุยที่นี่เนื่องจากบางโปรแกรมไม่เห็นด้วยกับผังการตัดสินใจเดียว ในความเป็นจริง GNU ที่grepกล่าวถึงในคำตอบของ M. Kitt เป็นตัวอย่างที่ดีของค่าผิดปกติที่ใช้กระบวนการตัดสินใจที่ค่อนข้างผิดปกติกับผลลัพธ์ที่ไม่คาดคิด โดยทั่วไปแล้วดังนั้น:

  • isatty()มาตรฐานการส่งออกจะต้องเป็นอุปกรณ์ปลายทางที่กำหนดโดย
  • โปรแกรมต้องสามารถค้นหาเร็กคอร์ดสำหรับชนิดเทอร์มินัลในฐานข้อมูล termcap / terminfo
  • ดังนั้นจึงต้องมีเป็นประเภทอาคารที่จะมองขึ้น TERMตัวแปรสภาพแวดล้อมจะต้องมีอยู่และความคุ้มค่าของมันจะต้องตรงกับบันทึกฐานข้อมูล
  • ดังนั้นจะต้องมีฐานข้อมูล terminfo / termcap ในการใช้งานบางอย่างของระบบย่อยตำแหน่งของฐานข้อมูล termcap สามารถระบุได้โดยใช้TERMCAPตัวแปรสภาพแวดล้อม ดังนั้นในการใช้งานบางอย่างมีตัวแปรสภาพแวดล้อมที่สอง
  • เร็กคอร์ด termcap / terminfo ต้องระบุว่าชนิดเทอร์มินัลรองรับสี มีmax_colorsฟิลด์ใน terminfo ไม่ได้ตั้งค่าสำหรับประเภทเทอร์มินัลที่ไม่มีความสามารถด้านสี อันที่จริงมีระเบียบแบบ terminfo สำหรับทุกประเภทเทอร์มินัล colourable มีบันทึกอื่นที่มี-mหรือ-monoผนวกเข้ากับชื่อที่ระบุความสามารถไม่มีสี
  • เร็กคอร์ด termcap / terminfo ต้องจัดเตรียมวิธีสำหรับโปรแกรมเพื่อเปลี่ยนสี มีset_a_foregroundและset_a_backgroundฟิลด์ใน terminfo

มันซับซ้อนกว่าการตรวจสอบเพียงisatty()เล็กน้อย มันจะทำต่อไปซับซ้อนโดยหลายสิ่งหลายอย่าง:

  • บางแอปพลิเคชันเพิ่มตัวเลือกบรรทัดคำสั่งหรือการตั้งค่าสถานะที่แทนที่การisatty()ตรวจสอบเพื่อให้โปรแกรมเสมอหรือไม่เคยถือว่ามันมีขั้ว (colourable) เป็นเอาท์พุท ตัวอย่าง:
    • GNU lsมี--colorตัวเลือกบรรทัดคำสั่ง
    • BSD lsลักษณะที่CLICOLOR(กรณีที่ไม่มีความหมายไม่เคย ) และCLICOLOR_FORCE(การแสดงตนความหมายเสมอ ) ตัวแปรสภาพแวดล้อมและกีฬา-Gตัวเลือกบรรทัดคำสั่ง
  • บางการใช้งานที่ไม่ได้ใช้ termcap / terminfo TERMและมีการตอบสนองเดินสายค่าของ
  • ไม่ใช่เทอร์มินัลทั้งหมดที่ใช้ลำดับ SGMA ของ ECMA-48 หรือ ISO 8613-6 ซึ่งมีชื่อเรียกว่า "ANSI escape sequences" ที่ผิดเล็กน้อยเพื่อเปลี่ยนสี กลไก termcap / terminfo ได้รับการออกแบบมาเพื่อป้องกันแอปพลิเคชันจากความรู้โดยตรงของลำดับการควบคุมที่แน่นอน (นอกจากนี้ยังมีข้อโต้แย้งว่าไม่มีใครใช้ลำดับ ISO 8613-6 SGR เพราะทุกคนเห็นด้วยกับข้อผิดพลาดของการใช้เซมิโคลอนเป็นตัวคั่นสำหรับลำดับ SGR สี RGB มาตรฐานจริงระบุโคลอน)

ดังที่กล่าวไว้ GNU grepจริงแสดงถึงความซับซ้อนเพิ่มเติมเหล่านี้ มันไม่ได้ปรึกษา termcap / terminfo, hardwires ลำดับการควบคุมเพื่อปล่อยและ hardwires การตอบสนองTERMต่อตัวแปรสภาพแวดล้อม

พอร์ต Linux / Unix ของมันมีรหัสนี้ซึ่งจะช่วยให้ colourization เฉพาะเมื่อTERMตัวแปรสภาพแวดล้อมที่มีอยู่และความคุ้มค่าไม่ตรงกับชื่อเดินสายdumb:

int
should_colorize (เป็นโมฆะ)
{
  char const * t = getenv ("TERM");
  ส่งคืน t && strcmp (t, "dumb")! = 0;
}

ดังนั้นแม้ว่าคุณTERMจะเป็นxterm-monoGNU grepจะตัดสินใจที่จะปล่อยสีแม้ว่าโปรแกรมอื่น ๆ เช่นvimจะไม่

พอร์ต Win32 ของมันมีรหัสนี้ซึ่งจะช่วยให้ colourization ทั้งเมื่อTERMตัวแปรสภาพแวดล้อมไม่อยู่หรือเมื่อมันมีอยู่และความคุ้มค่าไม่ตรงกับชื่อเดินสายdumb:

int
should_colorize (เป็นโมฆะ)
{
  char const * t = getenv ("TERM");
  กลับมาแล้ว! (t && strcmp (t, "dumb") == 0);
}

grepปัญหาของGNU เกี่ยวกับสี

การเปลี่ยนสีของ GNU grepนั้นมีชื่อเสียง เพราะมันไม่ได้ทำงานอย่างถูกต้องในการสร้างเอาท์พุทของเทอร์มินัล แต่เพียงแค่ทำให้เกิดความผิดพลาดในลำดับการควบคุมเดินสายที่จุดต่าง ๆ ของเอาท์พุตด้วยความหวังว่ามันจะดีพอ

สถานการณ์เหล่านี้เป็นสิ่งที่จำเป็นต้องทำในสิ่งที่อยู่ทางด้านขวามือของเครื่อง โปรแกรมที่ใช้งานเทอร์มินัลเอาต์พุตอย่างถูกต้องจะต้องคำนึงถึงระยะขอบขวาโดยอัตโนมัติ นอกจากจะเป็นไปได้เล็กน้อยว่าอาจขั้วไม่ได้พวกเขา ( ได้แก่auto_right_marginฟิลด์ใน terminfo) พฤติกรรมของอาคารที่จะมีอัตรากำไรขั้นต้นที่เหมาะสมโดยอัตโนมัติมักจะตามแบบอย่างธันวาคม VT ของที่รอการตัดสาย GNU grepไม่ได้คำนึงถึงสิ่งนี้ แต่คาดหวังว่าจะมีการตัดบรรทัดในทันทีและการแสดงสีที่ผิดพลาด

เอาต์พุตสีไม่ใช่เรื่องง่าย

อ่านเพิ่มเติม


2
ตามที่ฉันเข้าใจแล้ว OP จะถามเกี่ยวกับการเปลี่ยนแปลงพฤติกรรมเมื่อมีการเปลี่ยนเส้นทางผลลัพธ์ $TERMไม่ได้อธิบายว่า (คำตอบของคุณน่าสนใจโดยทั่วไป แต่ฉันไม่คิดว่ามันจะตอบคำถาม ... )
สตีเฟ่น Kitt

น่าสนใจมาก. ฉันต้องการภาพรวมเช่นนี้เกี่ยวกับวิธีที่โปรแกรมค้นพบ (หรือเพียงแค่ "ตัดสินใจ") ความสามารถของเครื่องเทอร์มินัลสำหรับสองสามเดือนนี้ นอกจากนี้ยังให้ข้อมูลเชิงลึกว่าเหตุใดจึงยากที่จะหาภาพรวมเช่นนี้ - เนื่องจากแต่ละโปรแกรมดูเหมือนจะทำแตกต่างกันเล็กน้อย
the_velour_fog

คำอธิบายว่าการตัดเส้นบรรทัดที่ค้างอยู่และการตัดเส้นบรรทัดหมายถึงอะไรพร้อมกับตัวอย่างที่แสดงให้เห็นถึงความแตกต่างจะดี
mosvy

0

unbufferคำสั่งจากคาดว่าแพคเกจ de-คู่รักที่ส่งออกจากโปรแกรมแรกและป้อนข้อมูลไปยังโปรแกรมที่สอง

คุณจะใช้มันแบบนี้:

unbuffer myshellscript.sh | grep value

ฉันใช้มันตลอดเวลาด้วยสคริปต์ansible และ ctee homebrewed ดังนั้นฉันจึงสามารถเห็นเอาต์พุตสีบนเทอร์มินัลในขณะที่ออกจากไฟล์บันทึกที่มีเอาต์พุตปกติ (ไม่มีสี)

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.