Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I've got 'color cat' working nicely, thanks to others
(see How can i colorize cat output including unknown filetypes in b&w?).

In my .bashrc:

cdc() {
  for fn in "$@"; do
  source-highlight --out-format=esc -o STDOUT -i $fn 2>/dev/null || /bin/cat $fn;
  done
}
alias cat='cdc' # To be next to the cdc definition above.

I'd like to be able to use this technique for other functions like head, tail and less.

How could I do that for all four functions? Any way to generalize the answer?

I have an option for gd doing git diff using

gd() { 
   git diff -r --color=always "$@"
}
share|improve this question
    
I've also tried multitail and grc but they're not working well. –  Michael Durrant Nov 12 '13 at 4:31
add comment

1 Answer

up vote 2 down vote accepted

Something like this should do what you want:

for cmd in cat head tail; do
  cmdLoc=$(type $cmd | awk '{print $3}')
  eval "
    $cmd() { 
      for fn in \"\$@\"; do 
        source-highlight --failsafe --out-format=esc -o STDOUT -i \"\$fn\" | 
            $cmdLoc - 
      done 
    }
  "
done

You can condense it like this:

for cmd in cat head tail; do
    cmdLoc=$(type $cmd |& awk '{print $3}')
    eval "$cmd() { for fn in \"\$@\"; do source-highlight --failsafe --out-format=esc -o STDOUT -i \"\$fn\" | $cmdLoc - ; done }"
done

Example

With the above in a shell script, called tst_ccmds.bash.

#!/bin/bash

for cmd in cat head tail; do
    cmdLoc=$(type $cmd |& awk '{print $3}')
  eval "$cmd() { for fn in \"\$@\"; do source-highlight --failsafe --out-format=esc -o STDOUT -i \"\$fn\" | $cmdLoc - ; done }"
done

type cat
type head
type tail

When I run this, I get the functions set as you'd asked for:

$ ./tst_ccmds.bash
cat () 
{ 
    for fn in "$@";
    do
        source-highlight --failsafe --out-format=esc -o STDOUT -i "$fn" 2> /dev/null | /bin/cat - ;
    done
}
head is a function
head () 
{ 
    for fn in "$@";
    do
        source-highlight --failsafe --out-format=esc -o STDOUT -i "$fn" 2> /dev/null | /usr/bin/head - ;
    done
}
tail is a function
tail () 
{ 
    for fn in "$@";
    do
        source-highlight --failsafe --out-format=esc -o STDOUT -i "$fn" 2> /dev/null | /usr/bin/tail -;
    done
}

In action

When I use these functions in my shell (source ./tst_ccmds.bash) they work as follows:

cat

cat ss

head

head ss

tail

tail ss

plain text

txt ss

What's the trick?

The biggest trick, and I would call it more of a hack, is the use of a dash (-) as an argument to cat, head, and tail through a pipe which forces them to output the content that came from source-highlight through STDIN of the pipe. This bit:

...STDOUT -i "$fn" | /usr/bin/head - ....

The other trick is using the --failsafe option of source-highlight:

   --failsafe
          if no language definition is found for the input, it  is  simply
          copied to the output

This means that if a language definition is not found, it acts like cat, simply copying its input to the standard output.

Note about aliases

This function will fail if any of head,tail or cat are aliases because the result of the type call will not point to the executable. If you need to use this function with an alias (for example, if you want to use less which requires the -R flag to colorize) you will have to delete the alias and add the aliased command separately:

less(){
     for fn in "$@"; do 
       source-highlight --failsafe --out-format=esc -o STDOUT -i "$fn" |
          /usr/bin/less -R || /usr/bin/less -R "$fn"; done
}
share|improve this answer
    
+1 for the function as a variable trick but this won't run head or tail on the files, it will color-cat them and only run head if the file type is unknown. I think the OP wants to run a colored head, tail etc. –  terdon Nov 12 '13 at 14:35
    
@terdon - ah, thanks for pointing that out. Do you think he wants to head/tail the output of source-highlight? That appears to work, if you pipe it to tail or head. –  slm Nov 12 '13 at 14:52
    
yes, that's what I understood. Something like source-highlight --out-format=esc -o STDOUT -i "$fn" | $cmd || $cmd. I would have edited but I wasn't sure if that syntax works. –  terdon Nov 12 '13 at 14:55
    
@terdon - can you double check my changes? Seems to work now. –  slm Nov 12 '13 at 15:12
    
Works fine here, added to my .bashrc I think this is going to be one of my favorites! –  terdon Nov 12 '13 at 16:28
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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