46

With IEx (Elixir's REPL), I'd like to be able to save my command history.

For example:

I can open up a new IEx session and execute a command. After executing the command I can press the up arrow and have my last-command pre-populated. After closing IEx and re-opening, I'd like to have access to my last commands.

Is there a way to do this?

loeschg
  • 29,961
  • 26
  • 97
  • 150

4 Answers4

83

For Erlang/OTP 20

This is built-in (from https://hexdocs.pm/iex/IEx.html#module-shell-history)

From Erlang/OTP 20, it is possible to get shell history by passing some flags that enable it in the VM. This can be done on a per-need basis when starting IEx:

iex --erl "-kernel shell_history enabled"

If you would rather enable it on your system as a whole, you can use the ERL_AFLAGS environment variable and make sure that it is set accordingly on your terminal/shell configuration.

On Linux [and macOS]:

export ERL_AFLAGS="-kernel shell_history enabled"

On Windows:

set ERL_AFLAGS "-kernel shell_history enabled"

To show where the history file is located, run the following code from erl (Mac OS example value shown):

1> filename:basedir(user_cache, "erlang-history")
"/Users/your.username/Library/Caches/erlang-history"

To set the file to a different location, use the shell_history_path /path/to/history-file option from the erlang docs (compatible with Elixir/iex):

export ERL_AFLAGS="-kernel shell_history_path '\"$HOME/.erlang-history\"'"

For Erlang/OTP 19 and below

Try using https://github.com/ferd/erlang-history

> git clone https://github.com/ferd/erlang-history.git
> cd erlang-history
> sudo make install    # may not need sudo depending on installation
Nitrodist
  • 1,585
  • 5
  • 24
  • 34
loeschg
  • 29,961
  • 26
  • 97
  • 150
  • 22
    Just tried this out and it seems that history is not written correctly in some cases when exiting IEx by hitting `Ctrl`+`C` twice, which many people do. I had no problems when always terminating IEx with `Ctrl`+`G` `Q` `Enter` though, which is a cleaner way to exit IEx anyway. – Patrick Oscity Jul 31 '17 at 15:17
  • I have noticed that sometimes it has to do with how fast you quit. Might be a file write race condition of sorts? – loeschg Jul 31 '17 at 18:59
  • Haha maybe it just takes longer to hit this insane key combo so I'm less likely to run into the problem ;-) – Patrick Oscity Jul 31 '17 at 20:31
  • 3
    On MacOS you have to create an empty history file, otherwise it does not work: $ touch ~/.iex_history – Andrei Sura Sep 19 '17 at 16:26
  • what's the advantage of `ctrl-G Q enter` over `ctrl-C a enter`? – jaydel Mar 13 '18 at 14:49
  • 1
    @jaydel I guess it's the same as shutting down your computer by pressing the power button, vs using the "shut down" function of your OS: state is saved, doesn't end with an error etc. – Augustin Riedinger Apr 15 '19 at 14:17
  • AFAIC `iex --erl "-kernel shell_history enabled"` works, but `ERL_AFLAGS="-kernel shell_history enabled"` as environment variable doesn't, within a docker. If anyone has an idea, I'd be happy but I can live without it. – Augustin Riedinger Apr 15 '19 at 14:24
  • @AndreiSura On Linux too. So it looks like the file `~/.iex_history` has to exist. – Ludovic Kuty Mar 12 '20 at 08:51
  • @AugustinRiedinger hello two years later. I've added a docker compose example. – Adam Millerchip Dec 20 '21 at 08:24
15

I don't know if things changed at some point, but I found the above did not work. After looking at the man page for iex, I noticed that it needed to be

export ELIXIR_ERL_OPTIONS="-kernel shell_history enabled"

(note the additional ELIXIR). Perhaps the original solution was cogent was relevant for erl (I found it worked for that), but iex added the qualifier? Since the original question was for iex though, figured it should be updated.

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167
  • 4
    Can confirm the accepted answer no longer works and the above did. Worth noting (as others mentioned) that if you use ctrl+c to quit (as I do), you'll need to use ctrl + g following by q and enter – Mark Jul 05 '21 at 09:19
  • I can also confirm it and as of now the history is retained even when I use ctrl+c ctrl+c to exit on my Mac. – Declan Whelan Jan 08 '23 at 06:56
4

I'm using the oh-my-zsh, so I put on the vim ~/.zshrc:

# Enable history in IEX through Erlang(OTP)
export ERL_AFLAGS="-kernel shell_history enabled"

then source ~/.zshrc and now always load. Thank's @loeschg.

rld
  • 2,603
  • 2
  • 25
  • 39
2

For docker compose, you will need to create a volume to save the history, and tell Erlang where it is via -kernel shell_history_path. The path needs to be an Erlang term, so make sure it's '"tripple quoted"':

version: '3'

services:
  elixir:
    environment:
      ERL_AFLAGS: -kernel shell_history enabled -kernel shell_history_path '"/somewhere/sensible"'
    volumes:
      - type: volume
        source: shell_history
        target: /somewhere/sensible

volumes:
  shell_history:
Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74