20

Is there a way to run the BASH built-in commands from Python?

I tried:

subprocess.Popen(['bash','history'],shell=True, stdout=PIPE)

subprocess.Popen('history', shell=True, executable = "/bin/bash", stdout=subprocess.PIPE)

os.system('history')

and many variations thereof. I would like to run history or fc -ln.

2
  • 1
    The second one looks right to me. What goes wrong with it? Commented Mar 28, 2011 at 15:25
  • What about running a bash process and interacting with it? It may be simpler and useful for longer running commands or interacting with the shell (i.e. inputting a password after sudo). I think pexpect may fit that need. Commented Jan 2, 2013 at 15:51

2 Answers 2

19

I finally found a solution that works.

from subprocess import Popen, PIPE, STDOUT
shell_command = 'bash -i -c "history -r; history"'
event = Popen(shell_command, shell=True, stdin=PIPE, stdout=PIPE, 
    stderr=STDOUT)

output = event.communicate()

Thank you everyone for the input.

Sign up to request clarification or add additional context in comments.

2 Comments

shell=True is redundant here (it starts unnecessary /bin/sh). You could drop it and use the list argument as in @lesmana's answer
Unfortunately, the '-r' option does not get any of the current commands executed since opening the shell. The '-r' option loads whatever is in the ~/.bash_history file into the new shell you just opened. However, the ~/.bash_history file is normally only updated when you close the shell (unless you have a PROMPT_COMMAND hack in your .bashrc). Since you can't close the shell you're currently running (to get the history file to update), you're out of luck. I haven't yet found a workaround.
18
subprocess.Popen(["bash", "-c", "type type"])

this calls bash and tells bash to run the string type type, which runs the builtin command type on the argument type.

output: type is a shell builtin

the part after -c has to be one string. this will not work: ["bash", "-c", "type", "type"]

5 Comments

This works with 'type' and 'alias', but not 'history' or 'fc -ln'.
@duanedesign they do work, but the bash session started from subprocess has its history disabled. this behaviour is by design. you will have to tell bash to enable its history somehow. i remember reading a question about that on some stackexchange site some time ago. i will report back when i find it again.
The description there suggests just fetching $HOME/.bash_history, but that doesn't appear to be up-to-date. I think it's only saved when a shell, or perhaps all shells?, exit.
Your warning that "the part after -c has to be one string" is very important. I missed it the first time around and in my case suprocess.run(['bash', '-c', 'command command-that-shouldnt-exist'], check=True) correctly fails, whereas suprocess.run(['bash', '-c', 'command', 'command-that-shouldnt-exist'], check=True) worked just fine.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.