From 633ae6058a05b0240c798f6b7b60d3b0a87cab8e Mon Sep 17 00:00:00 2001 From: Dmitri Vereshchagin Date: Fri, 16 Oct 2026 15:50:47 +0300 Subject: [PATCH] Disable colored output on a dumb terminal (#3552) Enable colored output by default only when the TERM environment variable is set to a value other than dumb, as git and grep do, so that users no longer need to pass -M or set NO_COLOR on terminals that cannot display escape sequences. Colored output is now disabled not only for TERM=dumb but also when TERM is unset or empty. The -C option still enables colors in all these cases. On Windows, colored output is still decided by ANSICON and the console mode, and TERM is not checked. --- docs/content/manual/dev/manual.yml | 6 +++-- jq.1.prebuilt | 2 +- src/main.c | 5 +++- tests/shtest | 40 ++++++++++++++++++++++++++---- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/docs/content/manual/dev/manual.yml b/docs/content/manual/dev/manual.yml index f4e91a6e..5cb40805 100644 --- a/docs/content/manual/dev/manual.yml +++ b/docs/content/manual/dev/manual.yml @@ -169,8 +169,10 @@ sections: By default, jq outputs colored JSON if writing to a terminal. You can force it to produce color even if writing to a pipe or a file using `-C`, and disable color with `-M`. - When the `NO_COLOR` environment variable is not empty, jq disables - colored output by default, but you can enable it by `-C`. + When the `NO_COLOR` environment variable is not empty, + or the `TERM` environment variable is unset, empty, or set to + `dumb`, jq disables colored output by default, but you can + enable it by `-C`. Colors can be configured with the `JQ_COLORS` environment variable (see below). diff --git a/jq.1.prebuilt b/jq.1.prebuilt index f9f6e826..e7e9d462 100644 --- a/jq.1.prebuilt +++ b/jq.1.prebuilt @@ -115,7 +115,7 @@ Output the fields of each object with the keys in sorted order\. \fB\-\-color\-output\fR / \fB\-C\fR and \fB\-\-monochrome\-output\fR / \fB\-M\fR: . .IP -By default, jq outputs colored JSON if writing to a terminal\. You can force it to produce color even if writing to a pipe or a file using \fB\-C\fR, and disable color with \fB\-M\fR\. When the \fBNO_COLOR\fR environment variable is not empty, jq disables colored output by default, but you can enable it by \fB\-C\fR\. +By default, jq outputs colored JSON if writing to a terminal\. You can force it to produce color even if writing to a pipe or a file using \fB\-C\fR, and disable color with \fB\-M\fR\. When the \fBNO_COLOR\fR environment variable is not empty, or the \fBTERM\fR environment variable is unset, empty, or set to \fBdumb\fR, jq disables colored output by default, but you can enable it by \fB\-C\fR\. . .IP Colors can be configured with the \fBJQ_COLORS\fR environment variable (see below)\. diff --git a/src/main.c b/src/main.c index 3d786070..abe4e959 100644 --- a/src/main.c +++ b/src/main.c @@ -543,7 +543,10 @@ int main(int argc, char* argv[]) { #ifdef USE_ISATTY if (isatty(STDOUT_FILENO)) { #ifndef WIN32 - dumpopts |= JV_PRINT_ISATTY | JV_PRINT_COLOR; + dumpopts |= JV_PRINT_ISATTY; + char *term = getenv("TERM"); + if (term != NULL && term[0] != '\0' && strcmp(term, "dumb")) + dumpopts |= JV_PRINT_COLOR; #else /* Verify we actually have the console, as the NUL device is also regarded as tty. Windows can handle color if ANSICON (or ConEmu) is installed, or diff --git a/tests/shtest b/tests/shtest index 17bfe70b..5a62f2ee 100755 --- a/tests/shtest +++ b/tests/shtest @@ -691,7 +691,7 @@ for colors in '/' '[30' '30m' '30:31m:32' '30:*:31' 'invalid'; do done unset JQ_COLORS -# Check $NO_COLOR +# Check $NO_COLOR and $TERM test_no_color=true $msys && test_no_color=false $mingw && test_no_color=false @@ -708,22 +708,52 @@ if $test_no_color && command -v script >/dev/null 2>&1; then sed 's/^\x5E\x44\x08\x08//'; } fi - faketty $JQ_NO_B -n . > $d/color + faketty env TERM=xterm-256color $JQ_NO_B -n . > $d/color printf '\033[0;90mnull\033[0m\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect - faketty env NO_COLOR= $JQ_NO_B -n . > $d/color + faketty env TERM=xterm-256color NO_COLOR= $JQ_NO_B -n . > $d/color printf '\033[0;90mnull\033[0m\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect - faketty env NO_COLOR=1 $JQ_NO_B -n . > $d/color + faketty env TERM=xterm-256color NO_COLOR=1 $JQ_NO_B -n . > $d/color printf 'null\r\n' > $d/expect od -tc $d/expect od -tc $d/color cmp $d/color $d/expect - faketty env NO_COLOR=1 $JQ_NO_B -Cn . > $d/color + faketty env TERM=xterm-256color NO_COLOR=1 $JQ_NO_B -Cn . > $d/color + printf '\033[0;90mnull\033[0m\r\n' > $d/expect + od -tc $d/expect + od -tc $d/color + cmp $d/color $d/expect + faketty env TERM=dumb $JQ_NO_B -n . > $d/color + printf 'null\r\n' > $d/expect + od -tc $d/expect + od -tc $d/color + cmp $d/color $d/expect + faketty env TERM=dumb $JQ_NO_B -Cn . > $d/color + printf '\033[0;90mnull\033[0m\r\n' > $d/expect + od -tc $d/expect + od -tc $d/color + cmp $d/color $d/expect + faketty env TERM= $JQ_NO_B -n . > $d/color + printf 'null\r\n' > $d/expect + od -tc $d/expect + od -tc $d/color + cmp $d/color $d/expect + faketty env TERM= $JQ_NO_B -Cn . > $d/color + printf '\033[0;90mnull\033[0m\r\n' > $d/expect + od -tc $d/expect + od -tc $d/color + cmp $d/color $d/expect + (unset TERM; faketty $JQ_NO_B -n . > $d/color) + printf 'null\r\n' > $d/expect + od -tc $d/expect + od -tc $d/color + cmp $d/color $d/expect + (unset TERM; faketty $JQ_NO_B -Cn . > $d/color) printf '\033[0;90mnull\033[0m\r\n' > $d/expect od -tc $d/expect od -tc $d/color