When using subprocess or os libraries, executing the command returns the result in terminal. I want to be able to assign the output to a variable without getting any output returned to the terminal.
pid = subprocess.call(['pidof', process])
pid = os.system('pidof ' + process)
I only want to assign the variable pid, not return text to terminal. I was using the 'commands' library earlier, however it is not supported by python3.
You can try check_output.
import subprocess
output = subprocess.check_output("COMMAND_TO_EXECUTE", shell=True)
Have you tried redirect the command output to DEVNULL?
FNULL = open(os.devnull, 'w')
retcode = subprocess.call(['pidof', process], stdout=FNULL, stderr=subprocess.STDOUT)
Related
Iam trying to execute an exif command using subprocess. The command is :
['exiftool', '-ID3:Picture', '-b', '-ThumbnailImage', '/home/mediaworker/Downloads/Raabta.mp3', '>', '/mnt/share_PROXY/exifData/Raabta.jpg']
Now, the issue is that it returns the status code as 1. But if i execute the same command in the terminal, it executes successfully. The file is written to the location. Is my command going wrong in subprocess ? The error i get when i run my python script is :
Error: File not found - >
Error: File not found - /mnt/share_PROXY/exifData/Raabta.jpg
The code implementation is as follows:
file_name = os.path.basename(file_loc)
file_name = file_name.replace(os.path.splitext(file_name)[1], ".jpg")
dst_loc = os.path.join(dst_loc, file_name)
cmd_ = ["exiftool", "-ID3:Picture", "-b", "-ThumbnailImage", file_loc, ">", dst_loc]
logger.info("Command is {}".format(cmd_))
try:
p = subprocess.Popen(cmd_, stdout=subprocess.PIPE)
p.communicate()
if p.returncode != 0:
logger.error("Failed to write thumbnail artwork")
else:
id3_metadata.append({"file_thumbnail_info_path": dst_loc})
except Exception:
logger.error("[extract_iptc_metadata] Exception : '{}'".format(ex))
The error output refers to the redirection >.
The proper way to redirect using subprocess is using the stdout parameter.
with open(dst_loc, 'wb') as f:
p = subprocess.Popen(cmd_, stdout=f)
p.communicate()
The '>', '/mnt/share_PROXY/exifData/Raabta.jpg' part of your command is shell redirection and is a function of the command line/shell. It is not available when you execute a command from python in this way.
The option you want to look at is the -W (-tagOut) option. This would be the example command you want to work off of. Just replace -preview:all with the tag you want to extract, which would be -ThumbnailImage in this case.
I am in a process of building a simple remote shell tool to communicate with Windows 10. Server sends a "message" through its own shell to the client who runs the message. I need this received message to be run by other process other that default cmd (shell=True) - a specified app.exe. Here is the code that runs on the client:
1)
def work( storage, message ) :
import subprocess
process = subprocess.Popen([message], stdout=subprocess.PIPE, stderr=None, shell=True)
#Launch the shell command:
output = process.communicate()
print output[0]
I tried including "app.exe" or "cmd" to execute the message but with that I get error: TypeError: bufsize must be an integer.
I have also tried pinpointing the issue locally and I can run:
2)
import subprocess
import sys
subprocess.Popen(["C:\\Users\\User\\Desktop\\app.exe", "-switch"] + sys.argv[1:], shell=False)
and pass arguments from a command terminal and it works as it should. Now I am trying to apply the same logic to a remote execution with my program and use either solution 1 or 2.
Update:
3) Trying to implement what I did locally to a remote solution:
def work( storage, message ) :
import subprocess
import sys
process = subprocess.Popen(["C:\\Users\\User\\Desktop\\app.exe", "-switch"] + sys.argv[1:], shell=False)
#Launch the shell command:
output = process.communicate()
print output[0]
I tried replacing sys.argv[1:] with message but I get:
TypeError: can only concatenate list (not "str") to list
shell=True doesn't mean the first argument to Popen is a list of arguments to the shell; it just means the first argument is processed by the shell, rather than being arguments to whatever system call your system would use to execute a new process.
In this case, you appear to want to run app.exe with a given argument; that's simply
cmd = r"C:\Users\User\Desktop\app.exe"
subprocess.Popen([cmd, "-switch", message], stdout=subprocess.PIPE)
#chepner sir, you are a very helpful. That was it! I am so happy, thanks for your help.
Your solution:
Popen(["...\\app.exe", "-switch", message], stdout=subprocess.PIPE, stderr=None)
That was the badger!
I want to redirect o/p of shell commands to file using variable "path" but it is not working
import os, socket, shutil, subprocess
host = os.popen("hostname -s").read().strip()
path = "/root/" + host
if os.path.exists(path):
print(path, "Already exists")
else:
os.mkdir("Directory", path , "Created")
os.system("uname -a" > path/'uname') # I want to redirect o/p of shell commands to file using varibale "path" but it is not working
os.system("df -hP"> path/'df')
I think the problem is the bare > and / symbols in the os.system command...
Here is a python2.7 example with os.system that does what you want
import os
path="./test_dir"
command_str="uname -a > {}/uname".format(path)
os.system(command_str)
Here's a very minimal example using subprocess.run. Also, search StackOverflow for "python shell redirect", and you'll get this result right away:
Calling an external command in Python
import subprocess
def run(filename, command):
with open(filename, 'wb') as stdout_file:
process = subprocess.run(command, stdout=subprocess.PIPE, shell=True)
stdout_file.write(process.stdout)
return process.returncode
run('test_out.txt', 'ls')
This question already has answers here:
Running shell command and capturing the output
(21 answers)
Closed 2 years ago.
I want to assign the output of a command I run using os.system to a variable and prevent it from being output to the screen. But, in the below code ,the output is sent to the screen and the value printed for var is 0, which I guess signifies whether the command ran successfully or not. Is there any way to assign the command output to the variable and also stop it from being displayed on the screen?
var = os.system("cat /etc/services")
print var #Prints 0
From this question which I asked a long time ago, what you may want to use is popen:
os.popen('cat /etc/services').read()
From the docs for Python 3.6,
This is implemented using subprocess.Popen; see that class’s
documentation for more powerful ways to manage and communicate with
subprocesses.
Here's the corresponding code for subprocess:
import subprocess
proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print("program output:", out)
You might also want to look at the subprocess module, which was built to replace the whole family of Python popen-type calls.
import subprocess
output = subprocess.check_output("cat /etc/services", shell=True)
The advantage it has is that there is a ton of flexibility with how you invoke commands, where the standard in/out/error streams are connected, etc.
The commands module is a reasonably high-level way to do this:
import commands
status, output = commands.getstatusoutput("cat /etc/services")
status is 0, output is the contents of /etc/services.
For python 3.5+ it is recommended that you use the run function from the subprocess module. This returns a CompletedProcess object, from which you can easily obtain the output as well as return code. Since you are only interested in the output, you can write a utility wrapper like this.
from subprocess import PIPE, run
def out(command):
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
return result.stdout
my_output = out("echo hello world")
# Or
my_output = out(["echo", "hello world"])
I know this has already been answered, but I wanted to share a potentially better looking way to call Popen via the use of from x import x and functions:
from subprocess import PIPE, Popen
def cmdline(command):
process = Popen(
args=command,
stdout=PIPE,
shell=True
)
return process.communicate()[0]
print cmdline("cat /etc/services")
print cmdline('ls')
print cmdline('rpm -qa | grep "php"')
print cmdline('nslookup google.com')
I do it with os.system temp file:
import tempfile, os
def readcmd(cmd):
ftmp = tempfile.NamedTemporaryFile(suffix='.out', prefix='tmp', delete=False)
fpath = ftmp.name
if os.name=="nt":
fpath = fpath.replace("/","\\") # forwin
ftmp.close()
os.system(cmd + " > " + fpath)
data = ""
with open(fpath, 'r') as file:
data = file.read()
file.close()
os.remove(fpath)
return data
Python 2.6 and 3 specifically say to avoid using PIPE for stdout and stderr.
The correct way is
import subprocess
# must create a file object to store the output. Here we are getting
# the ssid we are connected to
outfile = open('/tmp/ssid', 'w');
status = subprocess.Popen(["iwgetid"], bufsize=0, stdout=outfile)
outfile.close()
# now operate on the file
from os import system, remove
from uuid import uuid4
def bash_(shell_command: str) -> tuple:
"""
:param shell_command: your shell command
:return: ( 1 | 0, stdout)
"""
logfile: str = '/tmp/%s' % uuid4().hex
err: int = system('%s &> %s' % (shell_command, logfile))
out: str = open(logfile, 'r').read()
remove(logfile)
return err, out
# Example:
print(bash_('cat /usr/bin/vi | wc -l'))
>>> (0, '3296\n')```
The code below is outdated in Python 3.0 by being replaced by subprocess.getstatusoutput().
import commands
(ret, out) = commands.getstatusoutput('some command')
print ret
print out
The real question is what's the multiplatform alternative to this command from Python because the above code does fail ugly under Windows because getstatusoutput is supported only under Unix and Python does not tell you this, instead you get something like:
>test.py
1
'{' is not recognized as an internal or external command,
operable program or batch file.
This would be the multiplatform implementation for getstatusoutput():
def getstatusoutput(cmd):
"""Return (status, output) of executing cmd in a shell."""
"""This new implementation should work on all platforms."""
import subprocess
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, universal_newlines=True)
output = "".join(pipe.stdout.readlines())
sts = pipe.returncode
if sts is None: sts = 0
return sts, output
I wouldn't really consider this multiplatform, but you can use subprocess.Popen:
import subprocess
pipe = subprocess.Popen('dir', stdout=subprocess.PIPE, shell=True, universal_newlines=True)
output = pipe.stdout.readlines()
sts = pipe.wait()
print sts
print output
Here's a drop-in replacement for getstatusoutput:
def getstatusoutput(cmd):
"""Return (status, output) of executing cmd in a shell."""
"""This new implementation should work on all platforms."""
import subprocess
pipe = subprocess.Popen(cmd, shell=True, universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = str.join("", pipe.stdout.readlines())
sts = pipe.wait()
if sts is None:
sts = 0
return sts, output
This snippet was proposed by the original poster. I made some changes since getstatusoutput duplicates stderr onto stdout.
The problem is that dir isn't really a multiplatform call but subprocess.Popen allows you to execute shell commands on any platform. I would steer clear of using shell commands unless you absolutely need to. Investigate the contents of the os, os.path, and shutil packages instead.
import os
import os.path
for rel_name in os.listdir(os.curdir):
abs_name = os.path.join(os.curdir, rel_name)
if os.path.isdir(abs_name):
print('DIR: ' + rel_name)
elif os.path.isfile(abs_name):
print('FILE: ' + rel_name)
else:
print('UNK? ' + rel_name)
getstatusoutput docs say it runs the command like so:
{ cmd } 2>&1
Which obviously doesn't work with cmd.exe (the 2>&1 works fine if you need it though).
You can use Popen as above, but also include the parameter 'stderr=subprocess.STDOUT' to get the same behaviour as getstatusoutput.
My tests on Windows had returncode set to None though, which is not ideal if you're counting on the return value.