I'm trying to set the fish history pager to be bat -l fish for syntax highlighting. (i.e. set the PAGER environment variable bat -l fish just for the history command).

I tried:

# 1:
alias history "PAGER='bat -l fish' history" 
# results in "The function “history” calls itself immediately, which would result in an infinite loop"

# 2:
alias history "PAGER='bat -l fish' \history"
# results in the same.

# 3:
alias _old_history history
alias history "PAGER='bat -l fish' _old_history"
# results in (line 1): The call stack limit has been exceeded

I'm aware that abbr works in this case, but this changes my history command, and this is not what I want.

2 Answers 2


Two things are happening here:

  1. fish's alias actually creates a function.
  2. fish ships with a default history function already.

So when you write

alias history "PAGER='bat -l fish' history" 

what you actually have is the recursive function

function history
  PAGER='bat -l fish' history $argv 

Some solutions:

  1. use a different name for your alias

    alias hist 'PAGER="bat -l fish" history'
  2. Don't alias _old_history hist, but copy it instead

    functions --copy history _old_history
    alias history 'PAGER="bat -l fish" _old_history'
  3. If you don't care to keep fish's function, invoke the builtin history command in your own function

    function history
      builtin history $argv | bat -l fish

why doesn't the builtin history support pager?

I assume the fish designers didn't think that was a core part of the history functionality. I assume they put the user-facing stuff in a function that users can override.

Here's the relevant snippet from the default history function:

        case search # search the interactive command history
            test -z "$search_mode"
            and set search_mode --contains

            if isatty stdout
                set -l pager (__fish_anypager)
                and isatty stdout
                or set pager cat

                # If the user hasn't preconfigured less with the $LESS environment variable,
                # we do so to have it behave like cat if output fits on one screen.
                if not set -qx LESS
                    set -x LESS --quit-if-one-screen
                    # Also set --no-init for less < v530, see #8157.
                    if type -q less; and test (less --version | string match -r 'less (\d+)')[2] -lt 530 2>/dev/null
                        set -x LESS $LESS --no-init
                not set -qx LV # ask the pager lv not to strip colors
                and set -x LV -c

                builtin history search $search_mode $show_time $max_count $_flag_case_sensitive $_flag_reverse $_flag_null -- $argv | $pager
                builtin history search $search_mode $show_time $max_count $_flag_case_sensitive $_flag_reverse $_flag_null -- $argv
  • Wow, I didn't know about the builtin keyword The third solution indeed seems to be the simplest. I'm curious, why doesn't the builtin history support pager?
    – matan h
    Commented Jun 13 at 12:52

I succeeded using functions -c to copy the built-in history function. Turns out alias was just creating an history function that calls itself, while functions -c fully copies the function.

functions -c history _old_history
alias history "PAGER='bat -l fish' _old_history"

(here is the final version I ended up using in my config:

functions -c history old_history
alias history 'PAGER="bat --file-name \"fish history\" -l fish" old_history'


You must log in to answer this question.

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