7

Example:

#!/bin/bash

function my_test(){
    echo this is a test $1
}

my_test 1

python -c "from subprocess import check_output; print(check_output('my_test 2', shell=True))"

output:

this is a test 1
/bin/sh: my_test: command not found
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.5/subprocess.py", line 629, in check_output
    **kwargs).stdout
  File "/usr/lib/python3.5/subprocess.py", line 711, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'my_test 2' returned non-zero exit status 127
3
  • Why not saving my_test function in a separate shell file and run python -c with that shell script call from another one? Commented Jan 1, 2016 at 13:48
  • 1
    /bin/sh doesn't support the function keyword. Use #!/bin/bash (or some other shell) for your shebang. Commented Jan 1, 2016 at 14:07
  • May I ask why would you want to call a function defined only in that shell? Commented Jan 1, 2016 at 14:46

4 Answers 4

10

You need to export the shell function, so it will be inherited by child shells.

#!/bin/bash

function my_test(){
    echo this is a test $1
}

my_test 1

export -f my_test
python -c "from subprocess import check_output; print(check_output('my_test 2', shell=True))"
Sign up to request clarification or add additional context in comments.

12 Comments

Thanks, this works but I was wondering if there was a way to inherit it from python without touching the shell script. I guess that this is not possible right?
Can you put the function in another script? Then you can use source scriptname before trying to call the function.
No, it's not possible.
That's the point of exporting, it's the way to allow a function to be inherited.
If you run the script with, for example, bash -a my_script, the shell marks all names and functions for export without having to modify the script itself.
|
2

Exporting a function, which is not supported by all shells, places the code into the environment block. This is a language-neutral block of text, which is copied from parent to child when a new process is created.

This was the basis of ShellShock.

The trouble is that the two languages Bash and Python are totally different, so a function written in one will not be directly executable by the other without translation. The child process could scan the environment block looking for the function, then translate and compile it into its own language. A lot of work, and could easily be a security issue.

If you just want to go Bash->Python->Bash, then exporting the function from first Bash script should do it, because it will be copied into each environment block. However you also state in a comment that you don't want the first script to export it.

Well you could read the function code using python into a text string, then put it into the environment block yourself (this is what export does in the shell). Use the os.environ dictionary.

The actual name used is dependant on your version of Bash. The ShellShock vulnerability resulted in a lot of changes. Best create a test function, export it, then use env to find its full name. For example on my version a simple function called gash appears in the environment block as BASH_FUNC_gash%%.

BASH_FUNC_gash%%=() {  echo 'Hollow world'
}

For example:

import os
import subprocess

fun_body="""() {  echo 'Hollow world'
}
"""
os.environ['BASH_FUNC_gash%%'] = fun_body

p1 = subprocess.Popen('./myscript.sh')

p1.wait()

The script (myscript.sh) contains:

#!/bin/bash
gash

Alternatively you could look at your design again. Mixing languages is always problematic, why not write the whole lot in Python?

Comments

-1

You can use the os module.

import os
os.system("anything what you would like to do in the shell")

1 Comment

I don't see how this helps python -c "import os; print(os.system('my_test 2'))" still outputs sh: my_test: command not found
-3

The os module is definitely the easiest way and does not cause much trouble in a shell.

Comments

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.