I am trying to run a simple Python script which runs the ipconfig /all command as a proof of concept.
You can find it below:
from subprocess import PIPE, run
my_command = "ipconfig /all"
result = run(my_command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.stdout, result.stderr)
But I didn't suceed to run it, I tryed both with the command line and by clicking on it but it open a cmd window for 1 second, and then close it so I cannot even read it.
Edit: I am using Python 3.7 and my script is called ipconfig.py
Apparently, your problem is not related to the script itself, but rather to Python interpreter invocation. Check [Python 3.Docs]: How do I run a Python program under Windows?. A general approach would be to:
Open a cmd (PS) window in your script directory
Launch Python (using its full path: check [Python 3.Docs]: Using Python on Windows for more details) on your module (e.g.):
"C:\Program Files\Python37-64\python.exe" ipconfig.py
Of course, there are many ways to improve things, like adding its installation directory in %PATH% (if not already there) in order to avoid specifying its full path every time 1, but take one step at a time.
On the script side: check [Python 3.Docs]: subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None) (and the examples):
Pass the arguments as a list:
my_command = ["ipconfig", "/all"]
You might also want to check the command termination status (result.returncode)
1: If you didn't check Add Python 3.7 to PATH when installing it (check image from 2nd URL), you have to add Python's path (C:\Users\USER\AppData\Local\Programs\Python\Python37) manually. There are many resources on the web, here are 3:
[SuperUser]: How do I add Python to the Windows PATH?
[Geek University]: Add Python to the Windows Path
[RaspberryPi.Projects]: Is Python in your PATH?
Your code is working good.
The problem is that the cmd closes the window too fast and you can't see the result.
Just add a command to wait for your interaction before closing the window.
You can add this at the end of your code:
input("Press Enter to finish...")
Or pause the execution after completion:
import time
[at the end of the code pause for 5 seconds....]
time.sleep(5)
Related
I am trying to write a simple python script that will open the Windows cmd line, change to a specified directory, and then input the text: 'Test.exe -blah -blahblah etc...' in order to run my Test.exe executable with my specified parameters from the cmd line.
The code I have so far is the following:
import subprocess
subprocess.Popen(r'C:\Windows\System32\cmd.exe', cwd=r'C:\PythonTestScripts')
This code successfully launches the windows cmd.exe, and changes the directory to the specified cwd above, but I have no idea how to pass text into the cmd window from Python.
I have tried passing it as a string argument within the subprocess.Popen brackets, I have also tried assigning PIPE to the stdin and stdout with not much luck. I am familiar with simple coding from Uni, but I am not familiar with Python's syntax or scripting.
Any help is greatly appreciated.
One of your issues may be that cmd.exe doesn't exit once you've started it.
I was successful passing the /C argument to cmd.exe, which tell it to exit after processing the command.
This works:
from subprocess import Popen,PIPE
my_command = "dir *.log"
with Popen([r"C:\Windows\System32\cmd.exe","/C",my_command], stdout=PIPE, cwd=r'C:\Temp') as proc:
print(proc.stdout.read().decode().replace("\r\n","\n"))
I am trying to install node.js and then check appium version using appium -v
import os,subprocess
os.system('node.msi')
os.system('exit')
os.system('appium -v')
node.msi is a node file on my computer. when i do it through cmd, appium -v works if i do it in a new cmd, but it doesn't work if i keep using the same cmd. so i was hoping that after exit, my code should have worked. can someone point out what i am doing wrong here.
Most likely, the installation of node.msi modifies your system's PATH variable. This change does not become visible inside your running Python process.
If you know the path to your node installation, you can specify it explicitly in a call such as
subprocess.run([r'C:\node\bin\apium.exe', '-v'])
I assume that you are running Windows here. When a console starts, it reads its environment from the registry. That explains why it works when you open a second cmd console.
That means that you have to ask Python to lauch the command appium - v in a new console (and not only a new cmd.exe shell).
It can be done through os.system by using start:
os.system("start /W appium -v")
or depending on what is really appium:
os.system("start /W cmd /c appium -v")
You could also directly use the subprocess module (which offer more configuration than os.system)
p = subprocess.Popen("cmd / c appium -v", creationflags=subprocess.CREATE_NEW_CONSOLE)
p.wait()
Depending on what appium is, the following could be enough:
p = subprocess.Popen("appium -v", creationflags=subprocess.CREATE_NEW_CONSOLE)
p.wait()
I am pulling my hair out here. I am spawning a process which I need the feedback from in Python.
When I run the command in the cmd window it runs fine, but when I try to run it via Python the terminal hangs.
p = subprocess.Popen(startcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
Where startcmd is a string which when printed in the Python console looks like this:
"C:/Program Files/GRASS GIS 7.2.1/grass72.bat" --version
If I copy and paste this into a Windows cmd, it shows the version information and returns control to the command prompt about a second later, but in Python it freezes up.
I should point out, if I replace the startcmd string with something like "dir" or even "python --version", it works fine!
Additional: I have tried shell=True, this has the same result.
Additional: I have tried sending the cmd and arguments through as an array as suggested in an answer below given that shell=False, but this also hangs the same.
Additional: I have added the GRASS path to the system PATH, so that now I can simply call grass72 --version in the cmd window to get a result, however this also still freezes in Python but works fine in cmd.
Additional: I have created a basic .bat file to test if .bat files run ok via Python, here is what I created:
#echo off
title Test Batch Script
echo I should see this message
This runs fine both in cmd, and in Python.
Problem found but not solved!
So, I'm running the script which spawns the process using subprocess.Popen using Python 3.6. The .bat file which is spawned launches a Python script using a version of Python (based on 2.7) which comes shipped with GRASS:
%GRASS_PYTHON% "\BLAH\BLAH\grass72.py"
What is interesting, is that if I launch the subprocess.Popen script with Python 2.7, it works fine. Ahah, you may think, solved! But this doesn't solve my problem - because I really need Python 3.6 to be launching the process, also why does it matter what version of Python launches the batch file? The new Python script which is spawned is launched with Python 2.7 anyway.
Since I started re-directing stdout I can see that there is an error when I use Python 3.6 to launch the process:
File "C:\ProgramData\Anaconda3\lib\site.py", line 177
file=sys.stderr)
^
SyntaxError: invalid syntax
Notice its reverting to Anaconda3! Even though it is launched using python.exe from 2.7!
I experienced the same issue with Python 3.6 and 3.7 on Windows hanging for subprocess calls:
p = subprocess.Popen(startcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
Upon closer investigation I noticed this occurs only if the process writes more than about 4 KB (4096 bytes) of output which might explain why your short script does not reproduce this.
A workaround I found is using tempfile in the standard library:
# Write to a temporary file because pipe redirection seems broken
with tempfile.NamedTemporaryFile(mode="w+") as tmp_out,
tempfile.NamedTemporaryFile(mode="w+") as tmp_err:
p = subprocess.Popen(startcmd, stdout=tmp_out, stderr=tmp_err,
universal_newlines=True)
# `run` waits for command to complete, `Popen` continues Python program
while p.poll() is None:
time.sleep(.1)
# Cursor is after the last write call, reset to read output
tmp_out.seek(0)
tmp_err.seek(0)
out = tmp_out.read()
err = tmp_err.read()
You don't specify shell=True in your arguments to Popen. The recommended usage in that case is to specify a sequence of arguments instead of a string. So you should set startcmd equal to ["C:/Program Files/GRASS GIS 7.2.1/grass72.bat", "--version"].
Try this:
p = subprocess.Popen(startcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
i want to run and control PSFTP from a Python script in order to get log files from a UNIX box onto my Windows machine.
I can start up PSFTP and log in but when i try to run a command remotely such as 'cd' it isn't recognised by PSFTP and is just run in the terminal when i close PSFTP.
The code which i am trying to run is as follows:
import os
os.system("<directory> -l <username> -pw <password>" )
os.system("cd <anotherDirectory>")
i was just wondering if this is actually possible. Or if there is a better way to do this in Python.
Thanks.
You'll need to run PSFTP as a subprocess and speak directly with the process. os.system spawns a separate subshell each time it's invoked so it doesn't work like typing commands sequentially into a command prompt window. Take a look at the documentation for the standard Python subprocess module. You should be able to accomplish your goal from there. Alternatively, there are a few Python SSH packages available such as paramiko and Twisted. If you're already happy with PSFTP, I'd definitely stick with trying to make it work first though.
Subprocess module hint:
# The following line spawns the psftp process and binds its standard input
# to p.stdin and its standard output to p.stdout
p = subprocess.Popen('psftp -l testuser -pw testpass'.split(),
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# Send the 'cd some_directory' command to the process as if a user were
# typing it at the command line
p.stdin.write('cd some_directory\n')
This has sort of been answered in: SFTP in Python? (platform independent)
http://www.lag.net/paramiko/
The advantage to the pure python approach is that you don't always need psftp installed.
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>