Bash: Execute piped lines from stdin

I haven't found a solution to this after some searching. I think the search terms are just too general. I'd like to know how to execute a number of lines (at the bash prompt) which are generated by some other source. For example, I have a Python script which dynamically generates a number of bash commands and prints them to stdout. I'd like those lines to be executed as a bash script without having to save them to disk. For example:

$ python example.py
touch 1 2 3 4 5
rm 1 2 3 4 5
echo "Done"

I'd like to do something like:

$ python example.py | executeLines

Does such a command/feature exist in bash? Sometimes one of the commands may exit with a non-zero exit status, so appending && to each command and then running:

$ `python example.py`

will not always work and seems to be a clumsy solution.


Solution 1:

Have you tried

$ python example.py | bash

It ought to work, as it's a common enough trick. For example, the monitoring tool munin has a node configurator (munin-node-configure) that tells you what plugins you can run, and then takes a --shell flag that makes it spit out a bunch of ln -s commands to link in the plugins, when piped directly to bash.

There was even once a tool for configuring something - it was over 15 years ago, I can't remember what - where you'd become root and get the config done by opening a telnet session to an autoconfigurator and send the output straight to bash, with

# telnet example.com 7001 | bash

I can't imagine doing anything like that these days.

Solution 2:

I'd do this:

python example.py | while read command; do $command; done

The non-zero exit status can be worked around using ; instead of &&, by the way.

Solution 3:

Another technique you can use instead of piping to a bash subprocess is the eval shell built-in for cases where you need the generated shell code to rely on something in your current shell's environment, or you want the output of your program to include actions like setting environment variables in the current shell process.

For example, say your output was more like this:

$ python example.py
PATH="$PATH:/opt/wackysoft/bin"
export PATH
echo $PATH
which wackysoft-command

You might want to keep the changed PATH environment variable in your current session, so you'd use eval. For example:

$ eval "`python example.py`"
/bin:/sbin:/usr/bin:/usr/sbin:/opt/wackysoft/bin
/opt/wackysoft/bin/wackysoft-command
$ echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin:/opt/wackysoft/bin
$ which wackysoft-command
/opt/wackysoft/bin/wackysoft-command

This is similar to how programs like ssh-agent are usually called in .xsession or .profile configuration files.