accessing python dictionary from bash script - python

I am invoking the bash script from python script.
I want the bash script to add an element to dictionary "d" in the python script
abc3.sh:
#!/bin/bash
rank=1
echo "plugin"
function reg()
{
if [ "$1" == "what" ]; then
python -c 'from framework import data;data(rank)'
echo "iamin"
else
plugin
fi
}
plugin()
{
echo "i am plugin one"
}
reg $1
python file:
import sys,os,subprocess
from collections import *
subprocess.call(["./abc3.sh what"],shell=True,executable='/bin/bash')
def data(rank,check):
d[rank]["CHECK"]=check
print d[1]["CHECK"]

If I understand correctly, you have a python script that runs a shell script, that in turn runs a new python script. And you'd want the second Python script to update a dictionnary in the first script. That will not work like that.
When you run your first python script, it will create a new python process, which will interpret each instruction from your source script.
When it reaches the instruction subprocess.call(["./abc3.sh what"],shell=True,executable='/bin/bash'), it will spawn a new shell (bash) process which will in turn interpret your shell script.
When the shell script reaches python -c <commands>, it invokes a new python process. This process is independant from the initial python process (even if you run the same script file).
Because each of theses scripts will run in a different process, they don't have access to each other data (the OS makes sure that each process is independant from each other, excepted for specific inter-process communications methods).
What you need to do: use some kind of interprocess mechanism, so that the initial python script gets data from the shell script. You may for example read data from the shell standard output, using https://docs.python.org/3/library/subprocess.html#subprocess.check_output

Let's suppose that you have a shell plugin that echoes the value:
echo $1 12
The mockup python script looks like (I'm on windows/MSYS2 BTW, hence the strange paths for a Linux user):
import subprocess
p = subprocess.Popen(args=[r'C:\msys64\usr\bin\sh.exe',"-c","C:/users/jotd/myplugin.sh myarg"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
o,e= p.communicate()
p.wait()
if len(e):
print("Warning: error found: "+e.decode())
result = o.strip()
d=dict()
d["TEST"] = result
print(d)
it prints the dictionary, proving that argument has been passed to the shell, and went back processed.
Note that stderr has been filtered out to avoid been mixed up with the results, but is printed to the console if occurs.
{'TEST': b'myarg 12'}

Related

Calling a command line utility from Python

I am currently trying to utilize strace to automatically trace a programm 's system calls. To then parse and process the data obtained, I want to use a Python script.
I now wonder, how would I go about calling strace from Python?
Strace is usually called via command line and I don't know of any C library compiled from strace which I could utilize.
What is the general way to simulate an access via command line via Python?
alternatively: are there any tools similar to strace written natively in Python?
I'm thankful for any kind of help.
Nothing, as I'm clueless
You need to use the subprocess module.
It has check_output to read the output and put it in a variable, and check_call to just check the exit code.
If you want to run a shell script you can write it all in a string and set shell=True, otherwise just put the parameters as strings in a list.
import subprocess
# Single process
subprocess.check_output(['fortune', '-m', 'ciao'])
# Run it in a shell
subprocess.check_output('fortune | grep a', shell=True)
Remember that if you run stuff in a shell, if you don't escape properly and allow user data to go in your string, it's easy to make security holes. It is better to not use shell=True.
You can use commands as the following:
import commands
cmd = "strace command"
result = commands.getstatusoutput(cmd)
if result[0] == 0:
print result[1]
else:
print "Something went wrong executing your command"
result[0] contains the return code, and result[1] contains the output.
Python 2 and Python 3 (prior 3.5)
Simply execute:
subprocess.call(["strace", "command"])
Execute and return the output for processing:
output = subprocess.check_output(["strace", "command"])
Reference: https://docs.python.org/2/library/subprocess.html
Python 3.5+
output = subprocess.run(["strace", "command"], caputure_output=True)
Reference: https://docs.python.org/3.7/library/subprocess.html#subprocess.run

Python curses does not work with command substitution

I was using python project pick to select an option from a list. Below code returns the option and index.
option, index = pick(options, title)
Pick uses curses library from python. I want to pass the output of my python script to shell script.
variable output = $(pythonfile.py)
but it gets stuck on the curses screen. It cannot draw anything. What can be the reason for this?
pick gets stuck because when you use $(pythonfile.py), the shell redirects the output of pythonfile.py as if it were a pipe. Also, the output of pick contains characters for updating the screen (not what you want). You can work around those problems by
redirecting the output of pythonfile.py to /dev/tty
ensuring that your pythonfile.py writes its result to the standard error, and
directing the standard error in the shell script to the output of the $(...) construct.
For example:
#!/bin/bash
foo=$(python basic.py 2>&1 >/dev/tty )
echo "result '$foo'"
and in pythonfile.py, doing
import sys
print(option, index, file=sys.stderr)
rather than
print(option, index)
To pass the output of a Python script to a Bash variable you need to specify the command with which to open the python file inside the variable's declaration.
Like so:
variable_output=$(python pythonfile.py)
Furthermore, if you'd like to pass a variable from Python to bash you could use Python's sys module and then redirect the stderr.
Like so:
test.py
import sys
test_var = (str(3 + 3))
sys.exit(test_var)
test.sh
test_var=$(python3 test.py 2>&1)
echo $testvar
Now, if we run test.sh we get the output 6.

FreeBSD rc script with output to file

I have this script below where I start a python program.
The python program outputs to stdout/terminal. But I want the program to be started via rc script silently.
I can start the and stop the program perfectly. And it also creates the log file, but dosent fill anything to it. I tried a lot of different ways. Even with using daemon as starter.
Where is my problem?
#!/bin/sh
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
location="/rpiVent"
name="rpiVentService"
rcvar=`set_rcvar`
command="$location/$name"
#command_args="> $location/$name.log" // Removed
command_interpreter="/usr/bin/python"
load_rc_config $name
run_rc_command "$1"
Piping with > is a feature of the shell and not an actual part of the command line. When commands are programmatically involved, the arguments given them cannot contain shell directives (unless the parent process has special support for shell, like with Python subprocess.Popen(shell=True) (doc).
What in this case you can do is that you can wrap your command (/rpiVent/rpiVentService) to a shell script then invoke this shell script in FreeBSD rc script::
Creat /rpiVent/run.sh:
#!/bin/sh
/rpiVent/rpiVentservice > /rpiVent/rpiVentService.log
and then use this is a command (no args needed).
The correct way to do this is probably by "overriding" the start command using start_cmd variable, like this:
#!/bin/sh
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
location="/rpiVent"
name="rpiVentService"
rcvar=`set_rcvar`
load_rc_config $name
command="$location/$name"
command_interpreter="/usr/bin/python"
start_cmd=rpivent_cmd
rpivent_cmd()
{
$command_interpreter $command >$location/$name.log
}
run_rc_command "$1"

How to import a python file in a bash script ? (to use a python value in my bash script)

I would like to know if it's possible in a bash script to include a python script in order to write (in the bash script) the return value of a funnction I wrote in my python program ?
For example:
my file "file.py" has a function which returns a variable value "my_value" (which represents the name of a file but anyway)
I want to create a bash script which has to be able to execute a commande line like "ingest my_value"
So do you know how to include a python file in a bash script (import ...?) and how is it possible to call a value from a python file inside a bash script ?
Thank you in advance.
Update
Actually, my python file looks like that:
class formEvents():
def __init__(self):
...
def myFunc1(self): # function which returns the name of a file that the user choose in his computeur
...
return name_file
def myFunc2(self): # function which calls an existing bash script (bash_file.sh) in writing the name_file inside it (in the middle of a line)
subprocess.call(['./bash_file.sh'])
if__name__="__main__":
FE=formEvents()
I don't know if it's clear enough but here is my problem: it's to be able to write name_file inside the bash_file.sh
Jordane
The easiest way of doing this is via the standard UNIX Pipeline and your Shell.
Here's an example:
foo.sh:
#!/bin/bash
my_value=$(python file.py)
echo $my_value
file.py:
#!/usr/bin/env python
def my_function():
return "my_value"
if __name__ == "__main__":
print(my_function())
The way this works is simple:
You launch foo.sh
Bash spawns a subprocess and runs python file.py
Python (and the interpretation of file.py) run the function my_function and print it's return value to "Standard Output"
Bash captures the "Standard Output" of the Python process in my_value
Bash then simply echoes the value stored in my_value also to "Standard Output" and you should see "my_value" printed to the Shell/Terminal.
If the python script outputs the return value to the console, you should be able to just do this
my_value=$(command)
Edit: Damn, beat me to it
Alternatively, you can make the bash script process arguments.
#!/usr/bin/bash
if [[ -n "$1" ]]; then
name_file="$1"
else
echo "No filename specified" >&2
exit 1
fi
# And use $name_file in your script
In Python, your subprocess call should be changed accordingly:
subprocess.call(['./bash_file.sh', name_file])

Execute the shell script by passing certain parameters to it using Python?

I am working on a project with Python in which I am supposed to execute shell script with Python.
I have written a simple program from which I am able to execute shell script with my python code. But now I need to pass certain parameters from my Python code to the shell script and then print out those parameters by executing the shell script.
For the simplicity sake, Currently I am executing shell script which will print out Hello World but now I want to pass hostname and pp and sp values to my shell script and then print out those values from the shell script when it is getting execute by Python client.
#!/usr/bin/python
import subprocess
import json
import socket
hostname = socket.gethostname()
jsonData = '{"desc": "some information about the host", "pp": [0,3,5,7,9], "sp": [1,2,4,6,8]}'
jj = json.loads(jsonData)
print jj['pp'] # printing it from Python program for now
print jj['sp'] # printing it from Python program for now
print hostname # printing it from Python program for now
# pass the above values to my shell script
jsonStr = '{"script":"#!/bin/bash\\necho Hello World\\n"}'
j = json.loads(jsonStr)
print "start"
subprocess.call(j['script'], shell=True)
print "end"
In general, I want to pass, hostname, pp and sp values to my shell script as shown in jsonStr and then print out those values from the shell script itself when I run my Python code.
So it should print out like this whenever I execute my shell script in jsonStr-
start
Hello world
[0, 3, 5, 7, 9]
[1, 2, 4, 6, 8]
myhostname
end
Is this possible to do it in Python?
There are two ways to pass variables to a script: as arguments, or through the environment.
Since you're trying to execute a script as if it were a giant command line (which won't actually work—especially if you're escaping your newlines as \\n so the shell sees the whole thing as one line—but let's pretend it would), you can't pass arguments, so you will need to pass an environment.
This is trivial:
env = {}
env.update(os.environ)
env.update(jj)
subprocess.call('echo ${pp}', shell=True, env=env)
This will print out whatever was in jj[pp], and return 0.
Why? Well, in bash, ${pp} means "whatever is in the environment variable pp". And we copied every key-value pair from jj into the env environment, so the environment variable pp has whatever value was in jj[pp]. (In some cases you might want to quote things, e.g. "${pp}", but for echo there's no reason to do that, and without knowing what you're going to do in your real-life code I can't guess what you might need.)
If you actually had a script that you wanted to call, stored in a file, then of course you could pass it arguments the same way you do with any other program you run via subprocess, and inside the script you could reference them as $1, etc.
However, I don't see why you need to pass arguments to a script you're building on the fly. Just build the values into the script. While that's usually a bad idea, that's mainly because building a script on the fly is a bad idea, and you've already committed to that part for some reason. Format your strings in Python, where you have access to the full power of str.format or % (as you prefer), and the entire Python stdlib. For example:
script = 'echo {}'.format(shlex.quote(jj['pp']))
subprocess.call(script, shell=True)
Now the script doesn't have to do anything to access the value; it's hard-coded into the script.

Categories