History

fortsh maintains a persistent history of commands across sessions.

Source: src/io/readline.f90:1601-2027

History Navigation

Arrow Keys

  • Up - Previous command
  • Down - Next command

Emacs Mode

  • Ctrl+P - Previous command
  • Ctrl+N - Next command
  • Alt+< - First history entry
  • Alt+> - Last history entry (current input)

Vi Mode

In command mode:

  • k - Previous command
  • j - Next command

History Search

Incremental Search

Search history interactively:

  • Ctrl+R - Reverse incremental search
  • Ctrl+S - Forward incremental search
(reverse-i-search)`git': git commit -m "last commit message"

Type characters to filter. Press Ctrl+R again for next match.

Prefix Search

Type the beginning of a command and press Up:

git<Up>    # Finds last command starting with "git"

History Expansion

Recall and modify previous commands:

Event Designators

SyntaxMeaning
!!Last command
!nCommand number n
!-nn commands back
!stringLast command starting with string
!?string?Last command containing string
echo "Hello"
!!              # Repeats: echo "Hello"

ls /usr
!ls             # Last ls command: ls /usr

!-2             # Two commands back

Word Designators

SyntaxMeaning
!$Last argument of previous command
!^First argument of previous command
!*All arguments of previous command
!:nArgument n (0 = command)
!:n-mArguments n through m
echo one two three
echo !$         # three
echo !^         # one
echo !*         # one two three
echo !:2        # two

Modifiers

SyntaxMeaning
:hRemove trailing pathname component
:tRemove leading pathname components
:rRemove suffix
:eKeep only suffix
:pPrint without executing
:s/old/new/Substitute
echo /path/to/file.txt
echo !$:t       # file.txt
echo !$:h       # /path/to
echo !$:r       # /path/to/file
echo !$:e       # .txt

Quick Substitution

^old^new        # Replace 'old' with 'new' in last command
echo hello
^hello^goodbye  # echo goodbye

History Commands

View History

history          # Show all history
history 10       # Show last 10 commands
history | grep git   # Search history

History Options

history -c       # Clear history
history -d N     # Delete entry N
history -a       # Append to file
history -r       # Read from file
history -w       # Write to file

Configuration

HISTFILE

Location of history file:

export HISTFILE="$HOME/.fortsh_history"

Default: ~/.fortsh_history

HISTSIZE

Maximum entries in memory:

export HISTSIZE=10000

HISTFILESIZE

Maximum lines in history file:

export HISTFILESIZE=20000

HISTCONTROL

Control history recording:

export HISTCONTROL=ignoredups:erasedups

Options:

  • ignorespace - Ignore commands starting with space
  • ignoredups - Ignore duplicate consecutive commands
  • erasedups - Remove all previous duplicates
  • ignoreboth - ignorespace + ignoredups

HISTIGNORE

Patterns to exclude from history:

export HISTIGNORE="ls:cd:pwd:exit"
export HISTIGNORE="ls*:cd*:pwd"   # With wildcards

HISTTIMEFORMAT

Add timestamps to history display:

export HISTTIMEFORMAT="%F %T "
history
# 1  2024-01-15 10:30:00 git status
# 2  2024-01-15 10:30:05 git commit

Implementation Details

History Storage

Source: readline.f90:203-212

type :: history_t
  character(len=MAX_LINE_LEN), allocatable :: lines(:)
  integer :: count = 0
  integer :: current = 0
  logical :: initialized = .false.
end type

Core Functions

FunctionSourceDescription
add_to_historyreadline.f90:1601Add entry
add_to_history_with_controlreadline.f90:1608Add with HISTCONTROL
show_historyreadline.f90:1705Display entries
clear_historyreadline.f90:1718Clear all entries
save_history_to_filereadline.f90:1724Save to HISTFILE
load_history_from_filereadline.f90:1756Load from HISTFILE
append_history_to_filereadline.f90:1803Append new entries

History Expansion

The expand_history function (readline.f90:1828) processes expansion syntax:

  1. needs_history_expansion (line 1994) - Check for ! characters
  2. find_history_expansion_end (line 1886) - Find token boundaries
  3. process_history_expansion (line 1932) - Lookup and substitute

Tips

Avoid Recording Sensitive Commands

Prefix with a space (if ignorespace is set):

 export SECRET_KEY="..."   # Not saved (note leading space)

Search and Execute

!?keyword?       # Run last command containing "keyword"

Print Before Executing

!!:p            # Print last command without running
!git:p          # Print last git command

Reuse Arguments

mkdir /long/path/to/directory
cd !$           # cd /long/path/to/directory

cp file1.txt file2.txt /backup
ls !:2          # ls file2.txt