Persistent Python Command-Line History

I'd like to be able to "up-arrow" to commands that I input in a previous Python interpreter. I have found the readline module which offers functions like: read_history_file, write_history_file, and set_startup_hook. I'm not quite savvy enough to put this into practice though, so could someone please help? My thoughts on the solution are:

(1) Modify .login PYTHONSTARTUP to run a python script. (2) In that python script file do something like:

def command_history_hook():
    import readline

(3) Whenever the interpreter exits, write the history to the file. I guess the best way to do this is to define a function in your startup script and exit using that function:

def ex():
    import readline

It's very annoying to have to exit using parentheses, though: ex(). Is there some python sugar that would allow ex (without the parens) to run the ex function?

Is there a better way to cause the history file to write each time? Thanks in advance for all solutions/suggestions.

Also, there are two architectural choices as I can see. One choice is to have a unified command history. The benefit is simplicity (the alternative that follows litters your home directory with a lot of files.) The disadvantage is that interpreters you run in separate terminals will be populated with each other's command histories, and they will overwrite one another's histories. (this is okay for me since I'm usually interested in closing an interpreter and reopening one immediately to reload modules, and in that case that interpreter's commands will have been written to the file.) One possible solution to maintain separate history files per terminal is to write an environment variable for each new terminal you create:

def random_key()
    ''.join([choice(string.uppercase + string.digits) for i in range(16)])

def command_history_hook():
    import readline
    key = get_env_variable('command_history_key')
    if key:
        set_env_variable('command_history_key', random_key())

def ex():
    import readline
    key = get_env_variable('command_history_key')
    if not key:
        set_env_variable('command_history_key', random_key())

By decreasing the random key length from 16 to say 1 you could decrease the number of files littering your directories to 36 at the expense of possible (2.8% chance) of overlap.

Asked by: Abigail444 | Posted: 30-11-2021

Answer 1

I think the suggestions in the Python documentation pretty much cover what you want. Look at the example pystartup file toward the end of section 13.3:

or see this page:

But, for an out of the box interactive shell that provides all this and more, take a look at using IPython:

Answered by: Kellan681 | Posted: 01-01-2022

Answer 2

Try using IPython as a python shell. It already has everything you ask for. They have packages for most popular distros, so install should be very easy.

Answered by: Fiona536 | Posted: 01-01-2022

Answer 3

Persistent history has been supported out of the box since Python 3.4. See this bug report.

Answered by: Brooke430 | Posted: 01-01-2022

Answer 4

Use PIP to install the pyreadline package:

pip install pyreadline

Answered by: Anna832 | Posted: 01-01-2022

Answer 5

If all you want is to use interactive history substitution without all the file stuff, all you need to do is import readline:

import readline

And then you can use the up/down keys to navigate past commands. Same for 2 or 3.

This wasn't clear to me from the docs, but maybe I missed it.

Answered by: Carina403 | Posted: 01-01-2022

Similar questions

How would I get the detailed version of my Python interpreter via a one-liner or command-line option?

The output of --version itself is a little too brief: C:\>python --version Python 2.7.5 However, if I run Python from the command prompt, I get something similar to the following, with verbose version info for the interpreter all on one line: C:\> python Python 2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credi...

Tell python interpreter to use a interpreter command-line switch in the script itself

Is it possible to tell the python interpreter to run my script using specific command line switches. For example, If I have doctests enabled, I'd like to add if __name__ == '__main__': import doctest doctest.testmod() to create a self-contained test runner. However, this requires that I add -v switch to run the script: python ...

get the python command-line options passed to the python interpreter

How to programmatically retrieve the interpreter options passed to the python interpreter within that instance? For example, given command python -B -u what Python code lists the passed interpreter command-line options -B and -u? I could query sys.dont_write_bytecode to infer that command-line option -B...

linux - How to make a python, command-line program autocomplete arbitrary things NOT interpreter

I am aware of how to setup autocompletion of python objects in the python interpreter (on unix). Google shows many hits for explanations on how to do this. Unfortunately, there are so many references to that it is difficult to find what I need to do, which is slightly different. I need to know how to enable, tab/auto completion of arbitrary items in a command-line program written in ...

java - OCSP command-line test tool?

Closed. This question does not meet Stack Overflow guid...

python - How to prompt for user input and read command-line arguments

Closed. This question needs to be more focused. It ...

eclipse - Integrating command-line generated python .coverage files with PyDev

My build environment is configured to compile, run and create coverage file at the command line (using Ned Batchelder tool). I'm using Eclipse with PyDev as my editor, but for practical reasons, it's not possible/convenient for me to convert my whole build environment to Eclipse (and thus generate the coverage data directly from the IDE, as it's designed to do) PyDev seems to be using the same ...

c++ - How do I compile a Visual Studio project from the command-line?

I'm scripting the checkout, build, distribution, test, and commit cycle for a large C++ solution that is using Monotone, CMake, Visual Studio Express 2008, and custom tests. All of the other parts seem pretty straight-forward, but I don't see how to compile the Visu...

How to make a simple command-line chat in Python?

I study network programming and would like to write a simple command-line chat in Python. I'm wondering how make receving constant along with inputing available for sending at any time. As you see, this client can do only one job at a time: from socket import * HOST = 'localhost' PORT = 21567 BUFSIZE = 1024 ADDR = (HOST, PORT) tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(A...

data structures - Processing command-line arguments in prefix notation in Python

I'm trying to parse a command-line in Python which looks like the following: $ ./command -o option1 arg1 -o option2 arg2 arg3 In other words, the command takes an unlimited number of arguments, and each argument may optionally be preceded with an -o option, which relates specifically to that argument. I think this is called a "prefix notation". In the Bourne shell I wo...

Display constantly updating information in-place in command-line window using python?

I am essentially building a timer. I have a python script that monitors for an event and then prints out the seconds that have elapsed since that event. Instead of an ugly stream of numbers printed to the command line, I would like to display only the current elapsed time "in-place"-- so that only one number is visible at any given time. Is there a simple way to do this? If possible I'd like to u...

python - How to write script output to file and command-line?

I have a long-running Python script that I run from the command-line. The script writes progress messages and results to the standard output. I want to capture everything the script write to the standard output in a file, but also see it on the command line. Alternatively, I want the output to go to the file immediately, so I can use tail to view the progress. I have tried this: python MyLongRu...

python - Linux command-line call not returning what it should from os.system?

I need to make some command line calls to linux and get the return from this, however doing it as below is just returning 0 when it should return a time value, like 00:08:19, I am testing the exact same call in regular command line and it returns the time value 00:08:19 so I am confused as to what I am doing wrong as I thought this was how to do it in python. import os...

Still can't find your answer? Check out these communities...

PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python