Hide Subprocess searching information in python - python

This is my code, how can I hide the output of searching in subprocess, I want my code to show just the information of my system.
import subprocess
Id = subprocess.check_output(['systeminfo']).decode('utf-8').split('\n')
new = []
for item in Id:
new.append(str(item.split("\r")[:-1]))
for i in new:
print(i[2:-2])

the progress messages aren't part of the output, they're fed to standard error.
So they won't show in your result. But to silence them and avoid them to be printed when executing the script, just redirect standard error to NUL
import subprocess
result = subprocess.check_output(['systeminfo'],stderr=subprocess.DEVNULL).decode('utf-8',errors='ignore')
as a side note, result contains Windows end of line characters, that can be split upon just with:
result.splitlines()

Related

how does input parameter of subprocess.check_output works?

I'm trying to figure out how to use subprocess.
I want to sub-run a program, and get its output, within a main program using some data from the main program.
I know subprocessing is not the optimal solution but separating both programs is mendatory for this project.
So I tried a realy simple trial with 2 files :
the main one, named test_p1.py:
import subprocess
output = subprocess.check_output('test_p2.py',shell=True,text=True,input='4')
#I need shell=True for my project
print(output)
the second one, named test_p2 :
import sys
print(sys.stdin.read())
When I run this I expected to get my input back, but it is not working (nothing is printed).
I did a previous test where the second file is a simple print of a str, unrelated to sys.stdin and it worked fine.
So I guess the problem is either with the input or with sys.stdin.read()
Please help me :)
Edit:
I tried to convert test_p2.py to an executable as suggested but it did not work.
Edit 2 :
I also tried to use subprocess.run() instead of subprocess.checkoutput() in test_p1.py and to replace sys.stdin.read() by input() in test_p2.py.
This is test_p1.py
import subprocess
output = subprocess.run('test_p2.py',shell=True,check=True,input='please help\n',encoding="utf-8",text=True).stdout
print(output)
and this is test_p2.py
a=input()
print(a)
print('input worked')
but nothing is printed when I subprocess part 2 within part 1.
I don't understand How I can simply send info to a file I subprocess.

How to preserve python colorama color output when using tee on Windows

In my Windows 10 scenario, I want to print arbitrary python console output (print(), sys.exit(), etc) both to console and a log file. I don't have control over some parts of the code (external python packages), so I cannot use some dedicated logging mechanism.
After some research I found the tool tee.exe in UnxUtils which does this task almost the way I want.
My problem is to preserve color as generated by python's colorama package. Is there any way to accomplish that? Currently, tee.exe strips away the color.
The answer I am looking does not have to rely on tee.exe, it's just the closest I got to a real solution. What I am looking for should do the following:
any command line output appears both in the command line and the log file (both STOUT and STDERR)
the output appears on the command line in real time. Bonus points if this is also true for the log file.
color is preserved on the command line. Bonus points if the log file does not contain any color-related artifacts.
What I have so far is this:
Python file teetest.py:
import sys
import colorama
print("Test")
print("2nd Test")
colorama.init(autoreset=True)
print(colorama.Fore.RED + 'Color Test')
colorama.deinit(autoreset=True)
sys.exit("Error_Test")
Batch file teetest.bat:
#echo off
python teetest.py 2>&1 | tee log.txt
pause
My output looks like this (command line and log file are identical, no color):
Test
2nd Test
Color Test
Error_Test
The solution I am looking for will print the above to the command line so the words Color Test are red.
Edit:
It seems that tee.exe is not at fault. Instead, colorama strips away the ANSI characters for color control by design, so the color is lost when passed through tee.exe.
From the colorama manual:
Colorama makes this work on Windows, too, by wrapping stdout, stripping ANSI sequences it finds (which would appear as gobbledygook in the output), and converting them into the appropriate win32 calls to modify the state of the terminal.
Colorama's init() function offers the parameter strip, which if False, does cause colorama to not strip away the ANSI characters. This in turn allows to write a custom tee.py that does the same as tee.exe, as outlined by user #martineau below. In it, we can call colorama and handle the color properly.
This might be a workable solution, but it still has the downside that I would have to replace all colorama init() calls with init(strip=False) in my original python code and that in turn would cause ANSI characters to appear in the output if the code was called without redirecting through tee.py.
This might actually be the closest we can get to a proper solution here. If anyone can offer other ideas, I'm all ears but I fear chances are slim.
I don't know how it will work with respect to colorama, but after being unsatisfied with several tee utilities for Windows that I found online, I ended up writing my own in Python (3.x).
You may have to modify it to suit your own needs, but it should be a good start.
mytee.py:
"""
Copies stdin to stdout (screen) *and* the specified file.
"""
import fileinput
import os
from pathlib import Path
import sys
SHOW_FULL_PATH = False
DIVIDER = True
DIV_CH = ' '
if len(sys.argv) != 2:
raise SystemExit('Usage: mytee <filepath>')
try:
inp = fileinput.input(()) # Read from stdin.
path = Path(sys.argv[1])
stdout_write = sys.stdout.write
stdout_flush = sys.stdout.flush
# Assumes .py in same dir as output file.
script = (f'{path.parent/path.stem}{path.suffix}' if SHOW_FULL_PATH else
f'{path.stem}{path.suffix}')
with open(path, 'w') as outp: # Write to specified file.
outp_write = outp.write
outp_flush = outp.flush
def write(line):
stdout_write(line)
outp_write(line)
def writeln(line):
write(line + '\n')
banner = f'"{script}"' if ' ' in script else f'-[{script}]-'
writeln(f'{banner}')
if DIVIDER:
writeln(f'{DIV_CH * len(banner)}')
for line in inp:
write(line)
if DIVIDER:
writeln(f'{DIV_CH * len(banner)}')
writeln('-[done]-')
finally:
inp.close() # Not sure this is really necessary.
sys.exit(0)

PwnTools recv() on output that expects input directly after

Hi I have a problem that I cannot seem to find any solution for.
(Maybe i'm just horrible at phrasing searches correctly in english)
I'm trying to execute a binary from python using pwntools and reading its output completely before sending some input myself.
The output from my binary is as follows:
Testmessage1
Testmessage2
Enter input: <binary expects me to input stuff here>
Where I would like to read the first line, the second line and the output part of the third line (with ':' being the last character).
The third line of the output does not contain a newline at the end and expects the user to make an input directly. However, I'm not able to read the output contents that the third line starts with, no matter what I try.
My current way of trying to achieve this:
from pwn import *
io = process("./testbin")
print io.recvline()
print io.recvline()
print io.recvuntil(":", timeout=1) # this get's stuck if I dont use a timeout
...
# maybe sending data here
# io.send(....)
io.close()
Do I missunderstand something about stdin and stdout? Is "Enter input:" of the third line not part of the output that I should be able to receive before making an input?
Thanks in advance
I finally figured it out.
I got the hint I needed from
https://github.com/zachriggle/pwntools-glibc-buffering/blob/master/demo.py
It seems that Ubuntu is doing lots of buffering on its own.
When manually making sure that pwnTools uses a pseudoterminal for stdin and stdout it works!
import * from pwn
pty = process.PTY
p = process(stdin=pty, stdout=pty)
You can use the clean function which is more reliable and which can be used for remote connections: https://docs.pwntools.com/en/dev/tubes.html#pwnlib.tubes.tube.tube.clean
For example:
def start():
p = remote("0.0.0.0", 4000)
return p
io = start()
io.send(b"YYYY")
io.clean()
io.send(b"ZZZ")

How can I redirect terminal output that "refreshes" using '\r'?

I am attempting to write a (Bash) shell script that wraps around a third-party python script and captures all output (errors and stdout) into a log file, and also restarts the script with a new batch of data each time it completes successfully. I'm doing this on a standard Linux distribution, but hopefully this solution can be platform-independent.
So here's a simplified version of the shell script, omitting everything except the logging:
#!/bin/bash
/home/me/script.py &>> /home/me/logfile
The problem is the third-party python script's output is mostly on a single line, which is being refreshed periodically (~every 90 seconds) by use of a carriage return ("\r"). Here's an example of the type of output I mean:
#!/usr/bin/env python3
import time
tracker = 1
print("This line is captured in the logfile because it ends with a newline")
while tracker < 5:
print(" This output isn't captured in the log file. Tracker = " + str(tracker),end="\r")
tracker += 1
time.sleep(1)
print("This line does get captured. Script is done. ")
How can I write a simple shell script to capture the output each time it is refreshed, or at least to periodically capture the current output as it would appear on the screen if I were running the script in the terminal?
Obviously I could try to modify the python script to change its output behavior, but the actual script I'm using is very complex and I think beyond my abilities to do that easily.
The program should have disabled this behavior when output is not a tty.
The output is already captured completely, it's just that you see all the updates at once when you cat the file. Open it in a text editor and see for yourself.
To make the file easier to work with, you can just replace the carriage returns with line feeds:
/home/me/script.py | tr '\r' '\n'
If the process normally produces output right away, but not with this command, you can disable Python's output buffering.

Interfacing Python With Fortran through Command-Line Using Pexpect

I am using pexpect with python to create a program that allows a user to interact with a FORTRAN program through a website. From the FORTRAN program I am receive the error:
open: Permission denied apparent state: unit 4 named subsat.out.55 last format: list io lately writing sequential formatted external IO 55
when I attempt to:
p = pexpect.spawn(myFortranProgram,[],5)
p.logfile_read = sys.stdout
p.expect("(.*)")
p.sendline("55")
From what I understand, I am likely sending the 55 to the wrong input unit. How do I correctly send input to a FORTRAN program using pexpect in Python?
Thank You.
Edit: When p.sendline's parameter is empty (e.g. p.sendline()) or only contains spaces, the program proceeds as expected. In sending non-space values to a FORTRAN program, do I need to specify the input format somehow?
The pexpect module is something I'd not used before, but could be useful to me, so I tried this.
Edit:
I've not been able to duplicate the error you're reporting. Looking at this error leads me to believe that it has something to do with reading from a file, which may be a result of other issues. From what I've seen, this isn't what pexpect is designed to handle directly; however, you may be able to make it work with a pipe, like the example in my original answer, below.
I'm having no problem sending data to Fortran's I/O stream 5 (stdin). I created a Fortran program called regurgitate which issues a " Your entry? " prompt, then gets a line of input from the user on I/O stream 5, then prints it back out. The following code works with that program:
import pexpect
child = pexpect.spawn('./regurgitate')
child.setecho(False)
ndx = child.expect('.*Your entry?.*')
child.sendline('42')
child.expect([pexpect.EOF])
print child.before
child.close()
The output is simply:
42
Exactly what I expected. However, if my Fortran program says something different (such as "Your input?"), the pexpect just hangs or times out.
Original suggestion:
Maybe this pexpect.run() sample will help you. At least it seems to run my regurgitate program (a simple Fortran program that accepts an input and then prints it out):
import pexpect
out = pexpect.run('/bin/bash -c "/bin/cat forty-two | ./regurgitate"')
print out
The output was:
Your entry?
42
Where regurgitate prints out a "Your entry?" prompt and the forty-two file contains "42" (without quotes in both cases).

Categories