Executing string of python code within bash script - python

I've come across a situation where it would be convenient to use python within a bash script I'm writing. I call some executables within my script, then want to do a bit of light data processing with python, then carry on. It doesn't seem worth it to me to write a dedicated script for the processing.
So what I want to do is something like the following:
# do some stuff in bash script
# write some data into datafile.d
python_fragment= << EOF
f = open("datafile.d")
// do some stuff with opened file
print(result)
EOF
result=$(execute_python_fragment $python_fragment) # <- what I want to do
# do some stuff with result
Basically all I want to do is execute a string containing python code. I could of course just make another file containing the python code and execute that, but I'd prefer not to do so. I could do something like echo $python_fragment > temp_code_file, then execute temp_code_file, but that seems inelegant. I just want to execute the string directly, if that's possible.
What I want to do seems simple enough, but haven't figured it out or found the solution online.
Thanks!

You can run a python command direct from the command line with -c option
python -c 'from foo import hello; print (hello())'
Then with bash you could do something like
result=$(python -c '$python_fragment')

You only have to redirect that here-string/document to python
python <<< "print('Hello')"
or
python <<EOF
print('Hello')
EOF
and encapsulate that in a function
execute_python_fragment() {
python <<< "$1"
}
and now you can do your
result=$(execute_python_fragment "${python_fragment}")
You should also add some kind of error control, input sanitizing... it's up to you the level of security you need in this function.

If the string contains the exact python code, then this simple eval() function works.
Here's a really basic example:
>>> eval("print(2)")
2
Hope that helps.

maybe something like
result=$(echo $python_fragment | python3)
only problem is the heredoc assignment in the question doesn't work either. But https://stackoverflow.com/a/1167849 suggests a way to do it if that is what you want to do:
python_fragment=$(cat <<EOF
print('test message')
EOF
) ;
result=$(echo $python_fragment | python3)
echo result was $result

Related

Using grep on a Python command output into a shell script

I've been struggling for the past two hours on this simple example :
I have this line:
python -c 'import yum, pprint; yb = yum.YumBase(); pprint.pprint(yb.conf.yumvar, width=1)'
Which gives:
Loaded plugins: product-id
{'arch': 'ia32e',
'basearch': 'x86_64',
'releasever': '7Server',
'uuid': 'd68993fd-059a-4753-a7ab-1c4a601d206f',
'yum8': 'rhel',
'yum9': '7.1'}
And now, I would just like to get the line with the 'releasever'.
Directly on my Linux, there is no problem:
$ python -c 'import yum, pprint; yb = yum.YumBase(); pprint.pprint(yb.conf.yumvar, width=1)' | grep releasever
'releasever': '7Server',
I have the answer I am looking for.
But when it comes to put it in a script, I am so helpless.
Currently, I have:
#!/bin/ksh
check="$(python -c 'import yum, pprint; yb = yum.YumBase(); pprint.pprint(yb.conf.yumvar, width=1)')"
echo "${check}"
# The echo works as expected. But now, I would like to do a grep on that variable:
check2=${check}|grep releasever
echo "${check2}"
And the result is empty.
I've tried a lot of different things, like brackets, parentheses, quote, double quote, all-in-one command, but I can't get what I want.
I don't know what's happening behind that code, which is very simple. But still…
Can someone help me?
There seem to be 3 options.
It looks like yb.conf.yumvar is a dictionary. In which case, you could either print yb.conf.yumvar['releasever'] directory in your python script in which case the grep would be unnecessary.
Secondly, don't use grep. Instead, have your python script parse the yb.conf.yumvar into json and print it and then use jq from the outside to print the value of releasever
Third, and this is the sanest way, do what you want in Python directly. ksh scripts will be harder to manage over a longer period of time so just do what you want to do in Python and us os.system to execute external programs.
Your problem is that you are not putting check in any kind of std input. This would work fine:
check2=$(echo "$check" | grep releasever)
or you could put check content into a file and do like grep <string> < <file>.

Pass variable from Python to Bash

I am writing a bash script in which a small python script is embedded. I want to pass a variable from python to bash. After a few search I only found method based on os.environ.
I just cannot make it work. Here is my simple test.
#!/bin/bash
export myvar='first'
python - <<EOF
import os
os.environ["myvar"] = "second"
EOF
echo $myvar
I expected it to output second, however it still outputs first. What is wrong with my script? Also is there any way to pass variable without export?
summary
Thanks for all answers. Here is my summary.
A python script embedded inside bash will run as child process which by definition is not able to affect parent bash environment.
The solution is to pass assignment strings out from python and eval it subsequently in bash.
An example is
#!/bin/bash
a=0
b=0
assignment_string=$(python -<<EOF
var1=1
var2=2
print('a={};b={}'.format(var1,var2))
EOF
)
eval $assignment_string
echo $a
echo $b
Unless Python is used to do some kind of operation on the original data, there's no need to import anything. The answer could be as lame as:
myvar=$(python - <<< "print 'second'") ; echo "$myvar"
Suppose for some reason Python is needed to spit out a bunch of bash variables and assignments, or (cautiously) compose code on-the-fly. An eval method:
myvar=first
eval "$(python - <<< "print('myvar=second')" )"
echo "$myvar"
Complementing the useful Cyrus's comment in question, you just can't do it. Here is why,
Setting an environment variable sets it only for the current process and any child processes it launches. os.environ will set it only for the shell that is running to execute the command you provided. When that command finishes, the shell goes away, and so does the environment variable.
You can pretty much do that with a shell script itself and just source it to reflect it on the current shell.
There are a few "dirty" ways of getting something like this done. Here is an example:
#!/bin/bash
myvar=$(python - <<EOF
print "second"
EOF
)
echo "$myvar"
The output of the python process is stored in a bash variable. It gets a bit messy if you want to return more complex stuff, though.
You can make python return val and pass it to bash:
pfile.py
print(100)
bfile.sh
var=$(python pfile.py)
echo "$var"
output: 100
Well, this may not be what you want but one option could be running the other batch commands in python using subprocess
import subprocess
x =400
subprocess.call(["echo", str(x)])
But this is more of a temporary work around. The other solutions are more along what you are looking for.
Hope I was able to help!

How to execute multiline python code from a bash script?

I need to extend a shell script (bash). As I am much more familiar with python I want to do this by writing some lines of python code which depends on variables from the shell script. Adding an extra python file is not an option.
result=`python -c "import stuff; print('all $code in one very long line')"`
is not very readable.
I would prefer to specify my python code as a multiline string and then execute it.
Use a here-doc:
result=$(python <<EOF
import stuff
print('all $code in one very long line')
EOF
)
Tanks to this SO answer I found the answer myself:
#!/bin/bash
# some bash code
END_VALUE=10
PYTHON_CODE=$(cat <<END
# python code starts here
import math
for i in range($END_VALUE):
print(i, math.sqrt(i))
# python code ends here
END
)
# use the
res="$(python3 -c "$PYTHON_CODE")"
# continue with bash code
echo "$res"

Changing BASH script to Python

I am trying to convert this script to Python but am having problems with the BASH syntax ${variable}. This does something I do not understand as I have very little experience with BASH scripting. My question is basically,how can I do the dollar brackets variable thing in Python ${variable}. In my case the variable is a number from zero to two-hundred and fifty-five. Please see the BASH script below. I am trying to do the exact same thing in Python.
do
for code in {0..255};
do echo -e "\e[38;05;${code}m $code: Test";
done;
done
Here is my attempt to convert the code to a Python script. Unfortunately, I am still having to call BASH via the os.system() method or function. Please check out my script below. The script does not function the same way though, with changing the text in the BASH shell. The Python script below simply prints out the crazy text below and increments the numbers... :/
#! /usr/bin/env python
import os
def run():
for code in range(0, 255):
os.system('echo -e "\e[38;05;%dm %s Test"' % (code,str(code)))
run()
You can use print command and string formatting to evaluate your variable during the print.
BTW, you can use xrange rather than range in order not to generate all the numbers in your memory, but to yield it one-by-one (for large range)
You can use this:
import os
def run():
for code in range(0, 256):
print "\x1b[38;05;{code}m {code} Test".format(code=code)
run()
You’ll need to use string formatting.
Strangely enough, you already do this in your code (but using the old % syntax instead of the new .format method). I’m not even sure why you think you have to call echo since the string you pass to it is already the string that you are trying to get (if I understand your question right). Just use the print function to output the string.
try this:
#! /usr/bin/env python
import os
def run():
for code in range(0, 255):
os.system('/bin/echo -e "\e[38;05;%dm %s Test"' % (code,str(code)))
run()
the echo is usually both extrnal program and internal command of shell, which can make difference sometime

Call python script from ruby

For example, I can use Python scripts in PHP like there:
exec("python script.py params",$result);
where "script.py" - script name and variable $result save output data.
How I can make it with Ruby? I mean, call Python scripts from Ruby.
You can shell-out to any shell binary and capture the response with backticks:
result = `python script.py params`
One way would be exec.
result = exec("python script.py params")
Another way to do the same thing would be,
system 'python script.py', params1, params2
I used the following python call from a ruby module.
In my case using exec() didn't work because it interrupts the current process and caused the simulation I was running to fail.
# run python script
`python #{py_path_py} #{html_path_py} #{write_path_py}`
You can use backticks to accomplish this in two ways
result = `python script.py params`
or
result = %(python script.py params)

Categories

Resources