2

I have a python script (e.g. test.py) and a commands.txt file which contains a custom bash function (e.g. my_func) along with its parameters, e.g.

my_func arg1 arv2; my_func arg3 arg4; my_func arg5 arg6;

This function is included in the ~/.bash_profile. What I have tried to do is:

subprocess.call(['.', path/to/commands.txt], shell=True)

I know this is not the best case, in terms of setting the shell argument into True, but I cannot seem to implement it even in this way. What I get when I run test.py is: my_func: command not found

5
  • 1
    Have you exported the function from your .bash_profile? export -f my_func. If you don't do that then it is only visible to the interactive session you define it in, i.e. it does not get passed to child processes. Commented Nov 8, 2017 at 16:43
  • @cdarke No, I haven't done that. Also, my_func uses other bash functions in its definition. Does this affect anything? Commented Nov 8, 2017 at 16:55
  • subprocess.call(['for arg; do . "$arg"; done', '_', os.path.expanduser('~/.bashrc'), '/path/to/commands.txt'], shell=True) will work, if and only if your scripts (commands.txt and .bashrc) are both compatible with /bin/sh. Commented Nov 8, 2017 at 17:09
  • @thanasissdr, ...you'll want to export both the function itself and its dependencies -- with that done, subprocess.Popen(['bash', '-c', 'funcname "$@"', '_'] + args) will be able to run it (with args being a Python list of arguments to pass to the function, ie. args=['foo', 'bar', 'baz'] to run funcname foo bar baz). Using bash instead of shell=True makes sure you get a shell that actually knows how to read those exported functions, and passing arguments out-of-band from code is a security precaution: you don't want to pass a freeform field and have someone put $(rm -rf ~) in it. Commented Nov 8, 2017 at 20:30
  • @CharlesDuffy Thank you for the comment. Would it be possible to write a simple example? Commented Nov 9, 2017 at 9:28

2 Answers 2

2

You will need to invoke bash directly, and instruct it to process both files.

At the command-line, this is:

bash -c '. ~/.bash_profile; . commands.txt'

Wrapping it in python:

subprocess.call(['bash', '-c', '. ~/.bash_profile; . commands.txt'])

You could also source ~/.bash_profile at the top of commands.txt. Then you'd be able to run a single file.

It may make sense to extract the function to a separate file, since .bash_profile is intended to be used by login shells, not like this.

Sign up to request clarification or add additional context in comments.

2 Comments

The function is defined within the ~/.bash_profile.
Updated to reflect this. When you said "I have a ... commands.txt file which contains a custom bash function (e.g. my_func)", I thought you meant that it contained the function definition.
0

If the first line of your commands.txt file had the correct shebang (for example #!/bin/bash) making your file executable (chmod +x commands.txt) will be enough :

subprocess.call("path/to/commands.txt")

6 Comments

the extension txt doesn't matter?
@CedricJulien Thanks for the answer, is it possible to make the text file executable within the python script? subprocess.call(['chmod +x', ' absolute/path/to/commands.txt'], shell=True) would work as well?
@VanPeer Posix systems (like Linux) doesn't care of the extension
@thanasissdr yes, it could be possible
@CedricJulien I tried that but still I get the same error.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.