I'd like to control some bash programs (local, or ssh) with some (eventually interactive) scripts (say python) in a robust way. I'd like to send commands, get the stdout/stderr of that command at the end of the execution, as well as the exit code of the command. Note that the bash commands are chosen by an external user in real time, so it could be anything.

To get an idea of what I want, I'd like to provide a function (the programming language does not really matter):

def send_command(command):
    # how to implement ????
    return (stdin_output, stderr_output, exit_code)

so that I could run:

(o,e,ex) = send_command("pwd")
print("The output of your last command is ", o)
(o,e,ex) = send_command("cd /tmp")
(o,e,ex) = send_command("pwd")
print("The output of your last command is ", o)

that would produce:

The output of your last command is /home/me/
The output of your last command is /tmp/

Moreover, I want to make sure that no command could "mess-up" my python script, and make it believe that the command is finished when it's not. For example, I don't want to let him record all the next commands, so the following code should block on the first line forever (the first command is an infinite loop) and never call the second line:

send_command("echo $PS1; <malicious command that loops forever and sends all the next inputs to a webserver>")
send_command("echo mysecretpassword") # This line should never be executed

What I tried:

One option would be to run a new bash instance every-time, and run a script in this console. But this has two drawbacks: Firstly it's not super efficient as every-time it will load bash/ssh from scratch. Secondly the state of the bash (environment, working directory) is a new one at every run. Eg: if I run "cd /tmp", on the next command I'll be back at home.

The other option I see is expect/pexpect. The problem of this solution is that as far as I understand it, it is just a parsing of the output. And this parsing loses the semantic of the bash output. For example, if I expect $, I cannot make sure the command is finished, and it could be the command itself that wrote this text. Likewise if the programs are not fully trusted it could be even worse: a program could fake to be a bash, and read all the bash commands. One may try to setup a complicated PS1, but this environment variable is forwarded to the commands, so any program that output this variable like "env" would break this command, so it's not really a robust solution. Finally, I don't see a "good" way to get the exit code of the command, better than running a bash command that outputs the code of the last typed command, and parse this result.

Is there a third option I missed?


-- EDIT -- I found the environment variable PROMPT_COMMAND, that is not transmitted in the environment variables as far as I can see. But it's still possible to read it directly from the shell with a simple echo so it is not super robust either...

$ PS1=""
PROMPT_COMMAND='echo -n "Prompt MYSECRETNUMBERSETBYEXPECT (last exit $?) "'                             
Prompt MYSECRETNUMBERSETBYEXPECT (last exit 0) ls /tmp/o
Prompt MYSECRETNUMBERSETBYEXPECT (last exit 0) rm /tmp/a/donotexist
rm: impossible de supprimer '/tmp/a/donotexist': No such file or directory
Prompt MYSECRETNUMBERSETBYEXPECT (last exit 1) env | grep SECRET

-- EDIT 2 -- Another solution that seems more robust would be to use pexpect with a random secret prompt, and then embrace any command with:

PS1=""; <command>; PS1="My secret PS1 61547851396512fdsqjklqdf (last code $?) >>$ "

(this code just removes/recreates the PS1 secret prompt before/after the command to make sure the command does not have access to the prompt value). One can even redirect the output to a file if needed without creating a subshell by replacing <command> with { <command>; } > /tmp/out.stdout 2> /tmp/out.stderr (do not forget the spaces and semicolon). Is it the best way to proceed?

  • You have a number of concerns but it's not clear what you are trying to achieve. Your confusion seems to be based on the idea that you will run a single bash script and micromanage each command it runs. That's not really practical. Use a bash script to perform a single task and trust it to do what it does correctly or report a failure. Typically you write you (python?) program to execute single commands. If you need to change directory or set environment variables you do so in the program, not bash (eg python's os.chdir(path)). May 20, 2019 at 8:21
  • 1
    @PhilipCouling I'm not really running a script I'm the author, I more or less want to provide an interactive shell (it could be in a webbrower for example) to a user, that asks him some commands and gives back any output in stdin/stderr as well as the return code when the command is finish (so I need to wait for a prompt to make sure the command is finished). So I can't really know in advance what the user will want to run, or use any python code.
    – tobiasBora
    May 20, 2019 at 8:40
  • @Kiwy Well it's not a single script, it's an interactive one, and I don't want to print the commands, I want to detect in a robust way the end of each individual commands.
    – tobiasBora
    May 20, 2019 at 8:50
  • @PhilipCouling I tried to give a more precise example of what I want, see my edit.
    – tobiasBora
    May 20, 2019 at 9:07
  • you could check sysdig which is basically a sys admin spyware that could extract tons of information based on PID username and so one.
    – Kiwy
    May 20, 2019 at 11:36

1 Answer 1


You could try to use sysdig, it's basicaly a spyware for your system.
From the sysdiog wiki you could observe stdout from a process name cat using:

sysdig -s4096 -A -c stdout proc.name=cat

You could also observe any command executed by a user named foo like this :

sysdig -c spy_users user.name=foo

You could also refer to this StackExchange question:


This has a lot of idea for you.

You must log in to answer this question.

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