Python Subprocess.Call a Bash Alias

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



Leave a reply



Submit