I'm trying to call a self-defined command line function in python. I defined my function using apple script in /.bash_profile as follows:
function vpn-connect {
/usr/bin/env osascript <<-EOF
tell application "System Events"
tell current location of network preferences
set VPN to service "YESVPN" -- your VPN name here
if exists VPN then connect VPN
repeat while (current configuration of VPN is not connected)
delay 1
end repeat
end tell
end tell
EOF
}
And when I tested $ vpn-connect in bash, vpn-connect works fine. My vpn connection is good.
So I created vpn.py which has following code:
import os
os.system("echo 'It is running.'")
os.system("vpn-connect")
I run it with python vpn.py and got the following output:
vpn Choushishi$ python vpn.py
It is running.
sh: vpn-connect: command not found
This proves calling self-defined function is somehow different from calling the ones that's pre-defined by the system. I have looked into pydoc os but couldn't find useful information.
A way would be to read the ./bash_profile before. As #anishsane pointed out you can do this:
vpn=subprocess.Popen(["bash"],shell=True,stdin= subprocess.PIPE)
vpn.communicate("source /Users/YOUR_USER_NAME/.bash_profile;vpn-connect")
or with os.system
os.system('bash -c "source /Users/YOUR_USER_NAME/.bash_profile;vpn-connect"')
Or try
import subprocess
subprocess.call(['vpn-connect'], shell = True)
and try
import os
os.system('bash -c vpn-connect')
according to http://linux.die.net/man/1/bash
Related
I am creating a script to run shell commands for simulation purposes using a web app. I want to run a shell command in a django app and then save the output to a file.
The problem I am facing is that when running the shell command, the output tries to get saved in the url that is invoked (for example: localhost:8000/projects) which is understandable.
I want to save the output to for example:
/home/myoutput/output.txt rather than /projects or /tasks
I have to run a whole script and save it's output to the txt file later but that is easy once this is done.
Tried os.chdir() function to change directory to /desiredpath already
from subprocess import run
#the function invoked from views.py
def invoke_mpiexec():
run('echo "this is a test file" > fahadTest.txt')
FileNotFoundError at /projects
Exception Type: FileNotFoundError
First I want to say that directly calling external programs from a web request in Django is a bit of an anti-pattern. The preferred approach is to use a work queue like Celery or rq, but that comes with a bit of added complexity.
That being said, you can solve your problem with the argument shell=True:
from subprocess import run
#the function invoked from views.py
def invoke_mpiexec():
run('echo "this is a test file" > fahadTest.txt', shell=True)
Here is the documentation:
If shell is True, the specified command will be executed through the
shell. This can be useful if you are using Python primarily for the
enhanced control flow it offers over most system shells and still want
convenient access to other shell features such as shell pipes,
filename wildcards, environment variable expansion, and expansion of ~
to a user’s home directory. However, note that Python itself offers
implementations of many shell-like features (in particular, glob,
fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), and
shutil).
Note: Using shell=True can lead to security issues:
If the shell is invoked explicitly, via shell=True, it is the
application’s responsibility to ensure that all whitespace and
metacharacters are quoted appropriately to avoid shell injection
vulnerabilities.
You should use subprocess.call with stdout argument
def invoke_mpiexec():
f = open("fahadTest.txt", "w")
subprocess.call(['echo', '"this is a test file"'], stdout=f)
or use write function
def invoke_mpiexec():
f = open('fahadTest.txt', 'w')
f.write("Now the file has more content!")
f.close()
So I figured it out.
Below is the fix:
run('mkdir -p $HOME/phdata/test/ && echo "this is a test file" > $HOME/phdata/test/fahadTest.txt', shell=True)
mkdir -p creates a directory if it doesn't exist
$HOME is used to go to the home directory and from there you can
navigate to folders.
shell=True argument is required to run it as shell command
You can also create a ssh connection and run the commands/ scripts on the remote server. For this, my approach will be to create a script on the remote server, call it through my app and provide arguments to it. Another workaround which is not that good but works is to create a script on the server using the above line and then call it.
I look after a Lab with a number of Rigs in it and I am developing an automated process for running experiments. The trigger for loading the experiments is to use a particular username. I have a flowchart that identifies behaviours when logging on so that when a rig is booked to the particular username and nobody else is logged on, then it takes over and runs experiments during the night etc.
I need to be able to use python to run a batch file to log users off (unless there is a python command I can use). I have written a batch file that does this (LogOffIP.bat). If I run the batch file from a command prompt, it works fine and the users (chosen by the session id on the remote PC) get logged off and all is well.
I have a python script that calls the bat file with the same arguments and the command prompt pops up and runs but I get a different response like " 'logoff' is not recognized as an internal or external command", and the same for quser.
Please check out my code below and help me find a python solution.
Thanks...
LogOffIP.bat:
#echo off
echo Logging off Rig %1
echo at IP address %2
echo using session ID %3
echo.
echo.
logoff %3 /server:%2
echo Done...
echo
quser /server:%2
pause
rem exit
From python...
I have tried:
import os
os.system(r"path\LogOffIP.bat G 100.100.100.100 12")
this gives 'logoff' is not recognized.
I have tried:
import subprocess
answer = subprocess.call([path\LogOffIP.bat, G, 100.100.100.100, 1'])
this gives WindowsError: [Error 2] The system cannot find the file specified in python.
I have tried:
answer = subprocess.Popen([r'path','LogOffIP.bat','G 100.100.100.100 1'])
this gives WindowsError: [Error 5] Access is denied in python
I have used bogus IP addresses in the examples to protect the real ones.
I expect a short delay and the user is logged off as seen when running the batch file from a command prompt. os.system doesn't seem to support all the dos commands.
Try the following...
import subprocess
answer = subprocess.call([r'LogOffIP.bat', G, 100.100.100.100, 1'])
This is assuming that LogOffIP.bat is in the same directory as the .py file
I want to execute the following command via a python script:
sudo cat </dev/tcp/time.nist.gov/13
I can execute this command via the command line completely fine. However, when I execute it using subprocess, I get an error:
Command ['sudo','cat','</dev/tcp/time.nist.gov/13'] returned non-zero exit status 1
My code is as follows
import subprocess
subprocess.check_output(['sudo','cat','</dev/tcp/time.nist.gov/13'])
As I mentioned above, executing the command via the command line gives the desired output without any error. I am using the Raspbian Jessie OS. Can someone point me in the right direction?
You don't want to use subprocess for this at all.
What does this command really do? It uses a bash extension to open a network socket, feeds it through cat(1) to reroute it to standard output, and decides to run cat as root. You don't really need the bash extension, or /bin/cat, or root privileges to do any of this in Python; you're looking for the socket library.
Here's an all-Python equivalent:
#!/usr/bin/env python3
import socket
s = socket.create_connection(('time.nist.gov', 13))
try:
print(s.recv(4096))
finally:
s.close()
(Note that all of my experimentation suggests that this connection works but the daytime server responds by closing immediately. For instance, the simpler shell invocation nc time.nist.gov 13 also returns empty string.)
Give this a try:
import subprocess
com = "sudo cat </dev/tcp/time.nist.gov/13"
subprocess.Popen(com, stdout = subprocess.PIPE, shell = True)
I am connected to a first Raspberry Pi (172.18.x.x) in SSH and I would like to launch a script on the first RPI but the script is on another Raspberry Pi (192.168.x.x).
First, I did the configuration to connect without password to the second RPI from the first one.
When I am on the first one, I am launching this command :
ssh pi#192.168.x.x 'sudo python script_RPI2.py'
And this is working correctly, I can check the correct results but I would like to launch this script in another script on the first RPI. So, I put the previous command in the file : script_RPI1.py.
Then, I am launching the script : sudo python script_RPI1.py
And I got the following error :
ssh pi#192.168.x.x
^
SyntaxError: invalid syntax
Anyone has an idea concerning my problem ?
How are you launching the script? What appears from the minimal information you gave is that you are trying or to do that command within the Python interactive interpreter or that you want to execute it in the interpreter and you forgot to surround it with quotes(") in order to make it as a string.
Try to explain a bit more please.
You want to run a bash command:
ssh pi#192.168.x.x 'sudo python script_RPI2.py'
you show do it in a .sh file as in the following example:
#!/bin/sh
ssh pi#192.168.x.x 'sudo python script_RPI2.py'
After saving this file just do ./name_of_file.sh, which will simply run your bash file in the terminal, if you want to run a python script that opens a terminal in another process and executes string that are terminal commands you should look at something like this:
from subprocess import call
call(["ls"])
This will execute ls in another terminal process and return the result back to you. Please check what you want to actually do and decide on one of these paths.
Modified the entire answer and actually put some extra time on the code. The full solution for you to integrate will look something like the code below. Note that the code is setup in a way that you can define the host to connect to, along with the command you want to execute in the remote RPi
import subprocess
import sys
remoteHost="pi#192.168.x.x"
command="python /path/to/script.py"
ssh = subprocess.Popen(["ssh", "%s" % remoteHost, command],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
yourVar = result ### This is where you assign the remote result to a variable
I have written a shell in python (using the cmd module) and when using this shell, certain information about commands run ect. is outputted to a text file. I would like to write a piece of code that creates an alias to view the text file in my bash shell (eg as if I had executed the following command:
alias latest.trc='less <path to file>
My best current effort is:
x="alias %s = 'less %s'" % (<alias name>, <path>)
y=shlex.split(x)
atexit.register(subprocess.call, y)
This works to execute some commands on exit, eg if x="echo 'bye'" but I get the error
OSError: [Errno 2] No such file or directory
The path I am entering is certainly valid and if I run x directly from the command line it works.
Any help either with why my code is hitting an error or a better way to achieve the same effect would be greatly appreciated.
You get an error because alias is a bash command, not an executable. You must run subprocess.call inside a shell:
import subprocess
import atexit
import shlex
x="alias %s = 'less %s'" % ('a', 'whatever')
y=shlex.split(x)
atexit.register(lambda args: subprocess.call(args, shell=True), y)
But, given the fact that subprocess spawns a new process, whatever changes are made to the environment it runs into, are lost on exit.
You'd better instead create a file where you put all these aliases and source it by hand when you need to use them.