Normally when I cat a file like this

enter image description here

it's hard to read without colorizing.

I've managed to get cat to use source-highlight like this:

cdc() {
  for fn in "$@"; do
    source-highlight --out-format=esc -o STDOUT -i $fn 2>/dev/null || /bin/cat $fn
  done; }; alias cat='cdc'

which now produces the following for a recognized file extension - .sh in this case:

enter image description here

However without the .sh, e.g. if the file is just called .bash_functions the colorizing doesn't happen - because the file extension is not known.

Is there any way I can get color-highlight to color dot files (files that begin with a dot) as sh colors ?

btw this builds on top of How can i colorize cat output including unknown filetypes in b&w?

man source-higlight shows the following but I'm not clear what to do:

      output language definition file

      output language map file (default=`outlang.map')

      directory where language definition files and language maps are searched for.   If  not  specified
      these files are searched for in the current directory and in the data dir installation directory

      output directory

      language definition file

      language map file  (default=`lang.map')

      prints the language elements that are defined

      in the language definition file

      force to infer source script language (overriding given language specification)

Define your cdc function as

cdc() {
    for fn do
        if [[ "${fn##*/}" == .* ]]
            source-highlight --src-lang=sh --out-format=esc -i "$fn"
            source-highlight               --out-format=esc -i "$fn"
        fi 2> /dev/null  ||  /bin/cat "$fn"
  • for fn do is short for for fn in "$@"; do.
  • ${fn##*/} looks at the value of $fn and removes everything from the beginning up through (and including) the last /.  I.e., if $fn is a full pathname, this will be just the filename part.
  • [[ (the_above) == .* ]] checks whether the filename matches the .* glob/wildcard pattern; i.e., whether the filename begins with a ..  Note that this usage of == works only inside [[ … ]]; it does not work inside [ … ].
  • So, if $fn is a “dot file”, run source-highlight with the --src-lang=sh option.

    • You should always put shell variable references in double quotes unless you have a good reason not to, and you’re sure you know what you’re doing.  Unix/Linux filenames can contain spaces.  If you had a file named foo bar, and you said /bin/cat "foo bar", cat would display the contents of the file foo bar.  But, if you said cdc "foo bar" (with the current version of your cdc function), you would run source-highlight with -i foo bar, which would look for a file called foo and generally make a mess of things.  And so it would fail, and your function would try /bin/cat foo bar, which would likewise fail.  Using "$fn" makes this work for filenames that contain spaces.
    • The cp program requires you to specify, on the argument list, the name of the file or directory you want it to write to.  This is one of the few exceptions to the rule that most programs write to standard output by default (unless you specify otherwise).  You don’t need to say -o STDOUT, and I wonder why the author(s) of the program even made it possible for you to specify that.

    And, yes, I realize that you just copied all of that from the answer to your other question.

  • Obviously, if $fn is not a dot file, just run source-highlight the normal way, and let it check for an extension.
  • Note that the 2> /dev/null and the || /bin/cat "$fn" can be done for the if … then … else … fi block in its entirety; they don’t have to be repeated for each branch.

Hmm.  My version of source-highlight (3.1.7) has a --src-lang=LANGUAGE option (-s LANGUAGE, as used by yaegashi, for short).  I just noticed that it isn’t in the source-highlight man page excerpt you included in your question.  So, obviously, if your version of source-highlight doesn’t support that option, my answer won’t work for you.  (And, of course, neither will yaegashi’s.)  If that’s the case, you should see if you can install version 3.1.7 (or compatible) of source-highlight.

  • This worked for me. btw I am on source-highlight v3.1.6 – Michael Durrant Jun 7 '15 at 11:38
  • Great!  (Maybe you have the wrong version of the man page?) – Scott Jun 7 '15 at 11:55

Specify -s sh only when $fn looks like a dot file.

cdc() {
  for fn in "$@"; do
    OPTIONS="-f esc"
    case "${fn##*/}" in
      .*) OPTIONS="$OPTIONS -s sh" ;;
    source-highlight $OPTIONS -i "$fn" 2>/dev/null || \cat "$fn"
alias cat=cdc

You can add other custom file name matching rules in case.


yaegashi has the right idea, although I would do it like this:

cdc() {
    for path
        command=(source-highlight --out-format=esc -o STDOUT --failsafe)
        case "${path##*/}" in
            .*) command+=(-s sh)
        "${command[@]}" -i "$path"
  • The point of the ||  /bin/cat "$fn" is that source-highlight --out-format=esc -i some.text fails with source-highlight: could not find a language definition for input file some.text, because source-highlight can't figure out what "language" the file is in, so you want the function to fall back to using cat without exposing the ugly error message to the user.  But thanks for the reference on using an array for command arguments. – Scott Jun 7 '15 at 12:12
  • @Scott Fixed with a fallback option. – l0b0 Jun 7 '15 at 12:33

In addition to looking at the file extension, source-highlight has some other ways of detecting the language. You could annotate your shell script files like this:

  1. The shabang line: put #!/bin/sh or #!/bin/bash on the first line of the file.
  2. Emacs-style file type annotations: add a comment like # -*- shell -*- or # -*- bash -*- in the file (doesn't need to be the first line).

For details, see How the input language is discovered in source-highlight's manual.

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.