2

I need to run an OpenFOAM command by automatized python script.

My python code contains the lines

subprocess.Popen(['OF23'], shell=True)
subprocess.Popen(['for i in *; do surfaceConvert $i file_path/$i.stlb; done', shell=True)

where OF23 is a shell command is defined in alias as

alias OF23='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'

This script runs the OpenFOAM command in terminal and the file_path defines the stl files which are converted to binary format

But when I run the script, I am getting 'OF23' is not defined.

How do I make my script to run the alias command and also perform the next OpenFOAM file conversion command

Balaji Spades
  • 39
  • 1
  • 6

3 Answers3

6

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.

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • 2
    Thanks for your idea. It worked, I used just like you suggested `p=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 '+path+'/*;do surfaceConvert $i $i.stlb;done', shell=True) p.wait()` – Balaji Spades Sep 23 '15 at 13:29
4

You need to issue shopt -s expand_aliases to activate alias expansion. From bash(1):

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt [...]

If that does not help, check if the shell executed from your Python program is actually Bash (e.g. by echoing $BASH).

Michael Jaros
  • 4,586
  • 1
  • 22
  • 39
2

If your command may use bash-isms then you could pass executable parameter otherwise /bin/sh is used. To expand aliases, you could use @Michael Jaros' suggestion:

#!/usr/bin/env python
import subprocess

subprocess.check_call("""
    shopt -s expand_aliases
    OF23
    for i in *; do surfaceConvert $i file_path/$i.stlb; done
"""], shell=True, executable='/bin/bash')

If you already have a working bash-script then just call it as is.

Though to make it more robust and maintainable, you could convert to Python parts that provide the most benefit e.g., here's how you could emulate the for-loop:

#!/usr/bin/env python
import subprocess

for entry in os.listdir():
    subprocess.check_call(['/path/to/surfaceConvert', entry, 
                           'file_path/{entry}.stlb'.format(entry)])

It allows filenames to contain shell meta-characters such as spaces.

To configure the environment for a child process, you could use Popen's env parameter e.g., env=dict(os.environ, ENVVAR='value').

It is possible to emulate source bash command in Python but you should probably leave the parts that depend on it in bash-script.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670