3

Using tput colors seems to disturb the output of column. Why does this happen and more importantly is there a way around it?

$ {
  echo "$(tput bold)foo$(tput sgr0)" "$(tput bold)bar$(tput sgr0)"
  echo bar foo
} | column -t
foo  bar
bar                     foo

I have reproduced this issue on both macos and ubuntu 20.04 although it seems they both use BSD column

8
  • There used to be a very similar question somewhere at SE a few months ago. Anyway, the answer is the same: it works well for me with column from util-linux 2.36. What implementation of column are you using? Commented Dec 4, 2020 at 20:44
  • @ArkadiuszDrabczyk updated
    – jesse_b
    Commented Dec 4, 2020 at 20:47
  • Indeed, Ubuntu uses BSD implementation bugs.launchpad.net/ubuntu/+source/util-linux/+bug/1705437. It seems quite weird to me, we have util-linux implementation on Slackware. Can't you just install column from util-linux? Commented Dec 4, 2020 at 20:52
  • @ArkadiuszDrabczyk: I would prefer not to, this is going to be used on both macos and ubuntu docker containers so ultimately I would rather just remove the colors than require additional tools to be installed but I ideally I would like to get it working.
    – jesse_b
    Commented Dec 4, 2020 at 20:55
  • The util-linux code doesn't handle escape sequences for colors, making "works well for me" dubious. Commented Dec 4, 2020 at 21:45

3 Answers 3

1

You can pipe to cat -v to see all the characters of this file stream. column calculates the width using them:

^[[1mfoo^[(B^[[m ^[[1mbar^[(B^[[m
bar foo

The right way is to separate any content creation from any formatting (like the MVC model). Note that column is adding spaces to produce a tab-like output, so it modifies the content. While tput adds instructions to the terminal. By separating these tasks, we are able to save the output to a file, or pass it from our formatting function to send it to console, or format it for other destination.


But this is also a good exercise for awk, to implement column -t excluding some characters from the width calculations. The regular expression I use below catches a lot of tput stuff, but I am almost sure not all of them.

$ cat tst.awk
BEGIN {
    OFS = "  "
}

{
    nr = NR
    for (i=1;i<=NF;i++) {
        f[NR,i] = $i
        gsub(/\x1B[^[:alpha:]]+[[:alpha:]]/,"",$i)
        if (length($i) > col[i]) col[i] = length($i)
    }
}

END {
    for (i=1;i<=nr;i++) {
        for (j=1;j<=length(col);j++) {
            printf "%-"col[j]"s%s", f[i,j], (j==length(col)? ORS : OFS)
        }
    }
}

and you pipe the first output to awk -f tst.awk

1
$ {
    echo -e "$(tput bold)foo$(tput sgr0)" "$(tput bold)bar$(tput sgr0) baz";
    echo bar foo;
  } |cat -v
^[[1mfoo^[(B^[[m ^[[1mbar^[(B^[[m baz
bar foo

The problem is on tput sgr0 that as you know by default tputs uses escapes codes based on the Terminal type taken from the environment variable TERM.

if you do:

infocmp -1 |grep -E 'bold|sgr0'
    bold=\E[1m,
    sgr0=\E(B\E[m,

You will see what bold and sgr0 codes are (those are non-ANSI escapes values) which as you see in output after cat -v those converted to ^[[1m for tputs bold and ^[(B^[[m for sgr0 and column command do the same and resolves to ANSI escape type codes but fails when there is (B and left in ^[(B^[[m and then that doesn't recognized in ANSI escapes and caused final output not expected column-wise correctly.

if you do:

infocmp -1 -T ansi |grep -E 'bold|sgr0'
        bold=\E[1m,
        sgr0=\E[0;10m,

you will find the equivalent ANSI escape codes for each; so you have two options to resolve it:

  1. Replace tputs with ANSI escape codes above

    { 
      echo -e "\033[1mfoo\033[0;10m" "\033[1mbar\033[0;10m baz";
      echo bar foo;
    } |column -t
    
  2. Pass Terminal type to tputs:

    {
      echo -e "$(tput bold)foo$(tput -T ansi sgr0)" "$(tput bold)bar$(tput -T ansi sgr0) baz";
      echo bar foo;
    } |column -t
    
3
  • I tried the two proposals, I get the same result with the command in the question (column from util-linux 2.33.1) I see some comments under the question that some other implementations do not, do you reproduce the issue similar to the question? And I expect and see for my environment, the same result for tput or echo -e, as both would print the same output through cat -v.
    – thanasisp
    Commented Dec 8, 2020 at 21:33
  • @thanasisp Ohh, I'm using BSD column exactly this version; commandlinux.com/man-page/man1/column.1.html, but I see the similar output as OP posted, and above given commands both fix the intention; also my Terminal is Windows10 CMD Commented Dec 9, 2020 at 9:35
  • and also note that with same version of column but Linux Terminal type everything is fine even with OP's sample or mine in answer. so that is related to Terminal Type itself as mentioned and need specify Terminal type to tput command Commented Dec 9, 2020 at 9:57
0

I was running Ubuntu 18.04 and was puzzled by behaviour of column not acting as expected. As others have suggested, the problem is that the repo contains an antique.

The only way I found to obtain a modern version was by compiling from the util-linux repo.

It was difficult to figure this out because -V to obtain the version had not yet been added! There might be a more elegant way but I inferred the approximate version by calling up man column which has a date at the bottom "July 29, 2004". Compare the 2004 manpage to the 2019 manpage. While the former describes only four options, the latter has almost two dozen!

I can also say that on MacOS Catalina I get exactly the same thing. I was unable to locate a brew package that contains a more recent version of column but it might be hidden somewhere.

If you are unable to obtain access to a modern version, you should make sure to check the man page corresponding to whatever is present otherwise things will be frustrating!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .