I have been having some problems with subprocess.call(), subprocess.run(), subprocess.Popen(), os.system(), (and other functions to run command prompt commands) as I can't seem to get the msg command to work.
import subprocess
subprocess.call("msg * Hey",shell=True)
In theory, this should send "Hey" to every computer on the network unfortunately, this isn't running at all and I'm not quite sure why. I can run it on cmd successfully, but can't get it to work from Python.
I'd love to hear why this doesn't work and hopeful a way to fix my code or an alternate solution.
Edit: Solved, thanks for everyone's help. Upgrading to 64-bit Python did the trick.
In 64-bit Windows, "msg.exe" is only distributed as a native 64-bit binary. This file won't be found if you're using 32-bit Python, which executes under WOW64 emulation. WOW64 redirects "System32" access to the "SysWOW64" directory. In Windows 7+, use the virtual "SysNative" directory to access the real "System32". For example:
sysroot = os.environ['SystemRoot']
sysnative = os.path.join(sysroot, 'SysNative')
if not os.path.exists(sysnative):
sysnative = os.path.join(sysroot, 'System32')
msgexe_path = os.path.join(sysnative, 'msg.exe')
subprocess.call([msgexe_path, '*', 'Hey'])
Note that msg.exe has nothing to do with CMD, so there's no reason to use shell=True.
Try calling it as separate arguments:
subprocess.call(['msg', '*', 'Hey'], shell=True)
Try putting the complete path of the msg command. Example as listed
import subprocess
subprocess.call("/usr/local/bin/msg * Hey",shell=True)
Related
I am on mac OSX.
I have a program where I am trying to call downloaded libraries from the terminal. This is not possible if I don't know where the libraries are. I will use pip as a common library example
>>> os.system("pip -h")
32512
>>> os.system("which pip")
256
I have read this response to the 256 error, however, I still don't understand why it appears here. It says it is "frequently used to indicate an argument parsing failure" however the exact command works because this does not seem to be an argument parsing error to me.
I would like to be able to do something to the effect of:
os.system(os.system("which pip") +" -h")
If there is another way of doing this, I would love to hear it
Don't use os.system like that (and don't use which, either). Try this to find a program:
import os
for bin_dir in os.environ.get("PATH").split(":"):
if 'my_program' in os.listdir(bin_dir):
executable_path = os.path.join(bin_dir, 'my_program')
break
Note that this does assume that PATH was properly set by whatever process started the script. If you are running it from a shell, that shouldn't be an issue.
In general, using os.system to call common *NIX utilities and trying to parse the results is unidiomatic-- it's writing python as if it was a shell script.
Then, instead of using system to run pip, use the solution describe in this answer.
So as the title says, I'm having problem starting a new subprocess under Fedora. Now the situation is, I have a main python script from which I start a couple of other python processes using:
import subprocess
subprocess.Popen(['python', '-m', 'first_child.run', 'start'], shell=False)
Now this works fine on MacOS, debian and windows. On fedora if I run it from Aptana 3 IDE it also works, the only problem is when i try to run this main scrip from a terminal, where I get:
OSError: [Errno 2] No such file or directory
Do you have any ideea what can be the problem here?
Regards,
Bogdan
Sorry if this is something you've already thought of -- but the most common cause of OSError from calls to subprocess is that it cannot find the process
http://docs.python.org/library/subprocess.html#exceptions
Are you absolutely certain python is in your path?
I know you're probably going to point out you ran this script from the python executable -- but I thought I'd take a shot that perhaps you specified the full path to python when you ran it from the terminal.
For fun, right before the call to subprocess, you could dump your PATH
import os
print os.environ['PATH']
It's your current working directory. I don't think the problem is that it can't find python, the problem is that it can't find first_child.run.
Try printing os.getcwd() before you launch the subprocess, and see if it's different in the terminal vs. in the IDE.
On a side note, it's probably more reliable to use sys.executable as the python you use in your subprocess, as opposed to just saying python. For example, subprocess.Popen([sys.executable, '-m', 'first_child.run', 'start'], shell=False)
When I launch a PowerShell script from Python, the delay seems to be approximately 45s, and I cannot figure out why.
I'm trying to run a PowerShell script (accessing some APIs only available to PowerShell) from a Python script.
I've tried a lot of permutations, and all incur ~45 second delay compared to just running the script from a command prompt, using an identical command line.
For example - sample.ps1 might say:
echo foo
And runner.py might say:
import subprocess
p = subprocess.Popen([POWERSHELL, '-File', 'sample.ps1'], stdout=subprocess.STDOUT)
d = p.stdout.read()
Running the .ps1 script directly is fast, running it via runner.py (Python 2.7, 32bit on a 64bit machine) incurs 45 second delay.
The exact same thing occurs if I use "os.system", or Twisted's built-in process tools. So I suspect it's some subtle interaction between the Python interpreter and the Powershell interpreter, possibly related to creation of console windows, or handling of stdin/out/err streams? (which I know don't "really exist" in the same way on Windows)
I do not see any such delays. It is pretty snappy. ( that will also depend on what your script actually does.) Try using call:
from subprocess import call
call(["powershell", "sample.ps1"])
PowerShell loads your user's profile by default. Use the -NoProfile argument to turn that behavior off:
import subprocess
p = subprocess.Popen([POWERSHELL, '-NoProfile', '-File', 'sample.ps1'], stdout=subprocess.STDOUT)
d = p.stdout.read()
I am getting the following error:
WindowsError: [Error 2] The system cannot find the file specified
My code is:
subprocess.call(["<<executable file found in PATH>>"])
Windows 7, 64 bit. Python 3.x latest, stable.
Any ideas?
Thanks,
When the command is a shell built-in, add a shell=True to the call.
E.g. for dir you would type:
import subprocess
subprocess.call('dir', shell=True)
To quote from the documentation:
The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (e.g. dir or copy). You do not need shell=True to run a batch file or console-based executable.
On Windows, I believe the subprocess module doesn't look in the PATH unless you pass shell=True because it use CreateProcess() behind the scenes. However, shell=True can be a security risk if you're passing arguments that may come from outside your program. To make subprocess nonetheless able to find the correct executable, you can use shutil.which. Suppose the executable in your PATH is named frob:
subprocess.call([shutil.which('frob'), arg1, arg2])
(This works on Python 3.3 and above.)
On Windows you have to call through cmd.exe. As Apalala mentioned, Windows commands are implemented in cmd.exe not as separate executables.
e.g.
subprocess.call(['cmd', '/c', 'dir'])
/c tells cmd to run the follow command
This is safer than using shell=True, which allows shell injections.
If you are using powershell, then in it will be subprocess.call(['powershell','-command','dir']). Powershell supports a large portion of POSIX commands
After much head scratching, I discovered that running a file that is located in C:\Windows\System32\ while running a 32bit version of python on a 64bit machine is a potential issue, due to Windows trying to out-smart the process, and redirect calls to C:\Windows\System32 to C:\Windows\SysWOW64.
I found an example of how to fix this here:
http://code.activestate.com/recipes/578035-disable-file-system-redirector/
To quote from the documentation:
"Prior to Python 3.5, these three functions comprised the high level API to subprocess. You can now use run() in many cases, but lots of existing code calls these functions."
SO: instead of subprocess.call use subprocess.run for Python 3.5 and above
I met the same issue while I was calling a PHP. The reason is PHP isn't in PATH so the command PHP was not found. But PowerShell found it does exist in the current location and it suggests replacing the 'PHP' by the '.\PHP' if I trust this command. Then it runs well.
I'm working in a windows environment (my laptop!) and I need a couple of scripts that run other programs, pretty much like a windows batch file.
how can I run a command from python such that the program when run, will replace the script? The program is interactive (for instance, unison) and keeps printing lines and asking for user input all the time.
So, just running a program and printing the output won't suffice. The program has to takeover the script's input/output, pretty mcuh like running the command from a .bat file.
I tried os.execl but it keeps telling me "invalid arguments", also, it doesn't find the program name (doesn't search the PATH variable); I have to give it the full path ..?!
basically, in a batch script I can write:
unison profile
how can I achieve the same effect in python?
EDIT:
I found out it can be done with os.system( ... ) and since I cannot accept my own answer, I'm closing the question.
EDIT: this was supposed to be a comment, but when I posted it I didn't have much points.
Thanks Claudiu, that's pretty much what I want, except for a little thing: I want the function to end when the program exits, but when I try it on unison, it doesn't return control to the python script, but to the windows command line environment
>>> os.execlp("unison")
C:\>Usage: unison [options]
or unison root1 root2 [options]
or unison profilename [options]
For a list of options, type "unison -help".
For a tutorial on basic usage, type "unison -doc tutorial".
For other documentation, type "unison -doc topics".
C:\>
C:\>
C:\>
how to get around this?
You should create a new processess using the subprocess module.
I'm not fluent in windows processes but its Popen function is cross-platform, and should be preffered to OS specific solutions.
EDIT: I maintain that you should prefer the Subprocess module to os.* OS specific functions, it is cross-platform and more pythonic (just google it). You can wait for the result easily, and cleanly:
import os
import subprocess
unison = os.path.join(os.path.curdir, "unison")
p = subprocess.Popen(unison)
p.wait()
I found out that os.system does what I want,
Thanks for all that tried to help.
os.system("dir")
runs the command just as if it was run from a batch file
import subprocess
proc = subprocess.Popen(['unison', 'profile'], stderr=subprocess.PIPE,
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
proc.stdin.write('user input')
print proc.stdout.read()
This should help you get started. Please edit your question with more information if you want a more detailed answer!
os.execlp should work. This will search your path for the command. Don't give it any args if they're not necessary:
>>> import os
>>> os.execlp("cmd")
D:\Documents and Settings\Claudiu>Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
D:\Documents and Settings\Claudiu>