Python subprocess.call a bash alias
Update: Thanks for the upvotes for this hack to workaround the problem, I'm glad it's useful. But a much better answer is tripleee's, languishing far down the page...
If the alias you require is defined in ~/.bashrc, then it won't get run for a few reasons:
1) You must give the 'shell' keyword arg:
subprocess.call('command', shell=True)
Otherwise your given command is used to find an executable file, rather than passed to a shell, and it is the shell which expands things like aliases and functions.
2) By default, subprocess.call and friends use the '/bin/sh' shell. If this is a Bash alias you want to invoke, you'll need to tell subprocess to use bash instead of sh, using the 'executable' keyword arg:
subprocess.call('command', shell=True, executable='/bin/bash')
3) However, /bin/bash will not source ~/.bashrc unless started as an 'interactive' shell (with '-i'.) Unfortunately, you can't pass executable='/bin/bash -i', as it thinks the whole value is the name of an executable. So if your alias is defined in the user's normal interactive startup, e.g. in .bashrc, then you'll have to invoke the command using this alternative form:
subprocess.call(['/bin/bash', '-i', '-c', command])
# i.e. shell=False (the default)
Calling alias Command from python script
That's not going to work, even once you've resolved the alias
problem. Each Python subprocess.Popen
is run in a separate subshell, so the effects of executing OF23
won't persist to the second subprocess.Popen
.
Here's a brief demo:
import subprocess
subprocess.Popen('export ATEST="Hello";echo "1 $ATEST"', shell=True)
subprocess.Popen('echo "2 $ATEST"', shell=True)
output
1 Hello
2
So whether you use the alias, or just execute the aliased commands directly, you'll need to combine your commands into one subprocess.Popen
call.
Eg:
subprocess.Popen('''export PATH=/usr/lib64/openmpi/bin/:$PATH;
export LD_LIBRARY_PATH=/usr/lib64/openmpi/lib/:$LD_LIBRARY_PATH;
source /opt/OpenFOAM/OpenFOAM-2.3.x/etc/bashrc;
for i in *;
do surfaceConvert $i file_path/$i.stlb;
done''', shell=True)
I've used a triple-quoted string so I can insert linebreaks, to make the shell commands easier to read.
Obviously, I can't test that exact command sequence on my machine, but it should work.
Executing bash profile aliases from python script
Please see this answer: https://askubuntu.com/a/98791/1100014
The recommendation is to convert your aliases to bash functions and then export them with -f
to be available in subshells.
When you call Popen
, execute "bash -c <functionname>"
.
As for your last script attempt, you have a conflict in quotation marks. Replace the outer quotes with single quotes like this:
command = 'epatplot set=evli.FTZ plotfile="pn_filtered_pat.ps" 2>&1 | tee pn_filtered_pat.txt'
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
Python3 Run Alias Bash Commands
You cannot. When you run a python process it has no knowledge of a shell alias. There are simple ways of passing text from parent to child process (other than IPC), the command-line and through environment (i.e. exported) variables. Bash does not support exporting aliases.
From the man bash
pages: For almost every purpose, aliases are superseded by shell functions.
Bash does support exporting functions, so I suggest you make your alias a simple function instead. That way it is exported from shell to python to shell. For example:
In the shell:
ll() { ls -l; }
export -f ll
In python:
import subprocess
command = "ll" # the shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)
output = process.communicate()
print(output[0].decode()) # Required if using Python 3
Since you are using the print()
function I have assumed you are using python 3. In which case you need the .decode()
, since a bytes object is returned.
With a bit of hackery it is possible to create and export shell functions from python as well.
Running bash command with python subprocess
.bash_profile
is not read by Popen
and friends.
Environment variables are available for your script, though (via os.environ
).
You can use export
in your Bash shell to export a value as an environment variable, or use env
:
export MY_SPECIAL_VALUE=12345
python -c "import os; print(os.environ['MY_SPECIAL_VALUE'])"
# or
env MY_SPECIAL_VALUE=12345 python -c "import os; print(os.environ['MY_SPECIAL_VALUE'])"
Related Topics
How to Activate a Virtualenv Inside Pycharm's Terminal
Jupyter Notebook with Python 3.8 - Notimplementederror
Python: Simple List Merging Based on Intersections
What Do the Python File Extensions, .Pyc .Pyd .Pyo Stand For
Matplotlib Xticks Not Lining Up with Histogram
Example Use of "Continue" Statement in Python
Does Python Have a Bitfield Type
How to Make a Surface with a Transparent Background in Pygame
How to Use Multiprocessing Queue in Python
Python: Best Practice and Securest Way to Connect to MySQL and Execute Queries
Getting Computer's Utc Offset in Python
Download File Through Google Chrome in Headless Mode
How to Remove/Delete a Folder That Is Not Empty
Convert to Binary and Keep Leading Zeros
Django: Improperlyconfigured: the Secret_Key Setting Must Not Be Empty