Đầu ra màu của các quá trình rẽ nhánh


7

Tôi có một bản thảo bắt đầu một số quy trình và gửi chúng đến nền

mongod       & pid_mongo=$!
redis-server & pid_redis=$!
# etc.

Tất cả các quá trình này sau đó đầu ra đồng thời đến cùng một đầu ra tiêu chuẩn. Câu hỏi của tôi: có thể tô màu đầu ra của mỗi quá trình rẽ nhánh khác nhau, để - ví dụ - một trong số chúng xuất ra màu xanh lá cây và một trong số đó có màu đỏ?

Câu trả lời:


2

Bạn có thể làm điều này bằng cách chuyển qua bộ lọc, đó chỉ là vấn đề thêm mã ANSI thích hợp trước và sau mỗi dòng:

http://en.wikipedia.org/wiki/ANSI_escape_fterences#Colors

Tôi không thể tìm thấy một công cụ thực sự làm điều này sau vài phút googling, điều này hơi kỳ quặc khi xem xét việc viết nó dễ dàng như thế nào.

Đây là một ý tưởng sử dụng C:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>

/* std=gnu99 required */

// ANSI reset sequence
#define RESET "\033[0m\n"
// length of RESET
#define RLEN 5
// size for read buffer
#define BUFSZ 16384
// max length of start sequence
#define START_MAX 12

void usage (const char *name) {
    printf("Usage: %s [-1 N -2 N -b -e | -h]\n", name);
    puts("-1 is the foreground color, -2 is the background.\n"
        "'N' is one of the numbers below, corresponding to a color\n"
        "(if your terminal is not using the standard palette, these may be different):\n"
        "\t0 black\n"
        "\t1 red\n"
        "\t2 green\n"
        "\t3 yellow\n"
        "\t4 blue\n"
        "\t5 magenta\n"
        "\t6 cyan\n"
        "\t7 white\n"
        "-b sets the foreground to be brighter/bolder.\n"
        "-e will print to standard error instead of standard out.\n"
        "-h will print this message.\n"
    );
    exit (1);
}


// adds character in place and increments pointer
void appendChar (char **end, char c) {
    *(*end) = c;
    (*end)++;
}


int main (int argc, char *const argv[]) {
// no point in no arguments...
    if (argc < 2) usage(argv[0]);

// process options
    const char options[]="1:2:beh";
    int opt,
        set = 0,
        output = STDOUT_FILENO;
    char line[BUFSZ] = "\033[", // ANSI escape
        *p = &line[2];

    // loop thru options
    while ((opt = getopt(argc, argv, options)) > 0) {
        if (p - line > START_MAX) usage(argv[0]);
        switch (opt) {
            case '?': usage(argv[0]);
            case '1': // foreground color
                if (
                    optarg[1] != '\0'
                    || optarg[0] < '0'
                    || optarg[0] > '7'
                ) usage(argv[0]);
                if (set) appendChar(&p, ';');
                appendChar(&p, '3');
                appendChar(&p, optarg[0]);
                set = 1;
                break;
            case '2': // background color
                if (
                    optarg[1] != '\0'
                    || optarg[0] < '0'
                    || optarg[0] > '7'
                ) usage(argv[0]);
                if (set) appendChar(&p, ';');
                appendChar(&p, '4');
                appendChar(&p, optarg[0]);
                set = 1;
                break;
            case 'b': // set bright/bold
                if (set) appendChar(&p, ';');
                appendChar(&p, '1');
                set = 1;
                break;
            case 'e': // use stderr
                output = STDERR_FILENO;
                break;
            case 'h': usage(argv[0]);
            default: usage(argv[0]);
        }
    }
    // finish 'start' sequence
    appendChar(&p, 'm');

// main loop

    // set non-block on input descriptor
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    // len of start sequence
    const size_t slen = p - line,
    // max length of data to read
        rmax = BUFSZ - (slen + RLEN);
    // actual amount of data read
    ssize_t r;
    // index of current position in output line
    size_t cur = slen;
    // read buffer
    char buffer[rmax];
    while ((r = read(STDIN_FILENO, buffer, rmax))) {
        if (!r) break;  // EOF
        if (r < 1) {
            if (errno == EAGAIN) continue;
            break;  // done, error
        }
        // loop thru input chunk byte by byte
        // this is all fine for utf-8
        for (int i = 0; i < r; i++) {
            if (buffer[i] == '\n' || cur == rmax) {
            // append reset sequence
                for (int j = 0; j < RLEN; j++) line[j+cur] = RESET[j];
            // write out start sequence + buffer + reset
                write(output, line, cur+RLEN);
                cur = slen;
            } else line[cur++] = buffer[i];
        }
    }
    // write out any buffered data
    if (cur > slen) {
        for (int j = 0; j < RLEN; j++) line[j+cur] = RESET[j];
        write(output, line, cur+RLEN);
    }
    // flush
    fsync(output);

// the end
    return r;
}                                       

Tôi nghĩ rằng đó là về hiệu quả như bạn sẽ nhận được. Các write()nhu cầu để làm toàn bộ phù hợp với trình tự ANSI tất cả chỉ trong một bước - thử nghiệm này với dĩa song song dẫn đến đan xen nếu chuỗi ANSI và nội dung bộ đệm được thực hiện riêng rẽ.

Điều đó cần được biên dịch -std=gnu99getoptkhông phải là một phần của tiêu chuẩn C99 nhưng nó là một phần của GNU. Tôi đã thử nghiệm điều này phần nào với dĩa song song; nguồn đó, một tệp thực hiện và các bài kiểm tra nằm trong một tarball ở đây:

http://cognitivingissonance.ca/cogware/utf8_colorize/utf8_colorize.tar.bz2

Nếu ứng dụng bạn sử dụng với nhật ký lỗi này, hãy nhớ chuyển hướng đó:

application 2>&1 | utf8-colorize -1 2 &

Các tệp .sh trong thư mục thử nghiệm chứa một số ví dụ sử dụng.


Muốn giải thích thêm một chút (Tôi là người mới bắt đầu thực sự trong bash)? Tôi có cần thêm vào hướng dẫn đường ống trước hoặc sau khi đổ không?
user2398029

Trước đây, tức là. mongod | colorfilter & pid_mongo=$!
goldilocks

Tôi đã quyết định bỏ qua một chút và mã hóa thứ gì đó cho C này, vì vậy nếu bạn không thể tìm thấy bất cứ điều gì khác, hãy quay lại sau hôm nay hoặc ngày mai và tôi sẽ gắn một liên kết / một số nguồn cho điều đó. Thực sự cần có một công cụ biên dịch đơn giản cho việc này.
goldilocks

Tuyệt vời. Tôi sẽ thấy những gì tôi có thể làm về phía mình và mong muốn so sánh điều đó với việc bạn đảm nhận nó.
user2398029

@louism: được rồi, tôi đã thêm một số mã và một liên kết đến một tarball
goldilocks

5
red=$(tput setaf 1)
green=$(tput setaf 2)
default=$(tput sgr0)
cmd1 2>&1 | sed "s/.*/$red&$default/" &
cmd2 2>&1 | sed "s/.*/$green&$default/" &

+1 Để kiểm tra, xác định ví dụ cmd1() { while true; do echo foo; sleep 1; done }cmd2() { while true; do echo bar; sleep 3; done }
l0b0

0

Bạn có thể tốt hơn trong việc chuyển hướng các bản ghi đến các tập tin đầu ra cụ thể?

Có nhiều giải pháp khác nhau để tô màu đầu ra. Đơn giản nhất có lẽ là sử dụng gói grc ..


1
Chuyển hướng đến các tệp riêng biệt không phải là lựa chọn tốt nhất nếu a) bạn đang cố gắng quan sát / gỡ lỗi một cái gì đó trong thời gian thực. b) bạn muốn thứ tự các sự kiện từ nhiều quy trình được bảo tồn mà không phải so sánh dấu thời gian trong các tệp riêng biệt. Tôi đoán OP đang thử nghiệm máy chủ ngoại vi kết hợp với máy chủ cơ sở dữ liệu phía sau (mongo) và muốn xem điều gì xảy ra khi nào.
goldilocks

0

một tùy chọn khác bạn có thể sử dụng với chức năng sh dựng sẵn: cũng hoạt động trên tro (busybox);)

RED=`echo -e '\033[0;31m'`
NC=`echo -e '\033[0m'` # No Color

cmdx 2>&1 | sed "s/.*/$RED&$NC/" &

Tôi đã viết cho mình một hàm shell để dễ dàng chạy các chương trình trong nền. Đây là văn bản cho tro của busybox! Hoạt động trong bash là tốt. Chỉ cần chạy:

bg_red <whatever cmd you want to run in the bg>

đặt sau vào .bashrc của bạn

ESC="\033"                                                                      
# Colors:
COLOR_RED_F="${ESC}[31m"
COLOR_GREEN_F="${ESC}[32m" 
COLOR_RESET="${ESC}[0m" 

bg_red()            
{                                                                               
   [ "$#" -lt "1" ] && echo "bg_red() <cmd to run in bg>" && return 1           
   PIPE_RED=`echo -e $COLOR_RED_F`                                              
   PIPE_NC=`echo -e $COLOR_RESET`                                               
   $@ 2>&1 | sed "s/.*/$PIPE_RED&$PIPE_NC/" &                                   
}                                  

như đã thấy ở đây: http://www.bramschoenmakers.nl/en/node/511.html

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.