6

Using bash interactively I am trying to use cut to prevent the lines from going longer than my terminal width. But when using a command with colorized output all the color gets removed by cut. For example: ls -lG | cut -c 1-$COLUMNS.

Is there anyway to get cut to preserve the color formatting?

6

You've got two problems here

  1. ls -G stops outputting in colour when the output doesn't go to a terminal (here to a pipe instead). GNU ls needs to be passed a --color=always option, and for BSD ls, you need to set the environment CLICOLOR_FORCE to a non-empty value to tell it to always output in color.
  2. Colors are achieved by outputting escape sequences that are a sequence of characters like <ESC>[31m for foreground red. That doesn't have any width when displayed, but as far as cut is concerned, that's 5 characters which will count up to $COLUMNS.

    So you can't use cut here as you need to ignore those escape sequences in the calculation. Instead, you could do something like:

    esc=$'\e'
    CLICOLOR_FORCE=1 ls -l | sed "s/\(\(\($esc\[[0-9;]*m\)\{0,1\}.\{0,1\}\)\{$COLUMNS\}\).*/\1${esc}[m/"
    

    There, sed does the counting and adds a \e[m to revert the color to default in case it has been cut in the process.

Alternatively, you could tell your terminal not to wrap and do the cutting itself with:

tput rmam

(tput smam to restore)

You could define a function like:

nowrap() {
  [ -t 1 ] && tput rmam
  "$@"; local ret="$?"
  [ -t 1 ] && tput smam
  return "$ret"
}
alias nowrap='nowrap '

(the alias part to force alias expansion after nowrap), to be called as:

nowrap ls -l ...
  • My version of bash (mac OS) does not allow --color to be used with ls. But I put the ls command in a function enclosed with tput rmam and tput smam and that worked great. – ken_o Jan 13 '14 at 23:05
  • @ken_o, sorry I had assumed you were using GNU ls. Gilles edited the answer with the BSD alternative. – Stéphane Chazelas Jan 14 '14 at 7:49
2

man ls:

   --color[=WHEN]
          colorize  the  output;  WHEN  can be 'never', 'auto', or 'always' (the
          default); more info below

Your ls is probably configured for --color=auto, which means it only outputs color if it is directly connected to a terminal. (And not to another command like cut.)

You can use --color=always but be aware that the whole color stuff works by inserting special characters (escape sequences) which turn color on and off. If you cut in the middle of a colored word you will remove the "stop coloring" sequence and the next line will be colored, too.

Maybe ls --color=always|less -RS will do what you want.

  • 1
    That would be the right answer on Linux, but the BSD version of ls doesn't have an exact equivalent of --color=always. – Gilles Jan 13 '14 at 23:48
1

To fake output to a terminal and thus preserve the color formatting ls can be run in a pseudo-terminal using the (FreeBSD) script command (or tools such as ptymagic.c).

script -q /dev/null ls -lG | tr -d '\r' | cut -c 1-$COLUMNS

ptymagic ls -lG | cut -c 1-$COLUMNS

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.