Code snippet: How to show stdout for an external command

Hi all! I just typed this up for another user, and thought others may be interested.

Let’s say you want to make a Streamlit app that at some point runs a script called foo.sh in a subprocess. That script prints out a bunch of stuff to the terminal, and you would like that output to show up in your Streamlit app.

Here’s a little function you can use for that:

import streamlit as st
import subprocess
def run_and_display_stdout(*cmd_with_args):
    result = subprocess.Popen(cmd_with_args, stdout=subprocess.PIPE)
    for line in iter(lambda: result.stdout.readline(), b""):
        st.text(line.decode("utf-8"))

And here’s how you’d use it:

if st.button("Run"):
    run_and_display_stdout("sh", "foo.sh", "arg1", arg2", "etc")

Note: you can use this to run any subprocess, not just shell scripts! For example, to show the output of ls -Al / you would call:

run_and_display_stdout("ls", "-Al", "/")
6 Likes

Hi,

How can I add a fixed size text box/widget with a scroll bar so that the stdout is all in a fixed area?

My stdout is pretty long and it is taking up a huge amount of space when I simply use st.text()

Thank you

I don’t have a great solution for you, but depending on what your output looks like you could show it as a dataframe (because it’s scrollable).

def run_and_display_stdout(*cmd_with_args):
    df = pd.DataFrame({"text": []})
    element = st.dataframe(df)
    result = subprocess.Popen(cmd_with_args, stdout=subprocess.PIPE)
    for line in iter(lambda: result.stdout.readline(), b""):
        element.add_rows({"text": [line.decode("utf-8")]})

(This code was not tested!)


Another approach would be to make a custom component for that.

2 Likes