问题
I have a program which needs to output three messages that are constantly changing. Number of connections, time elapsed, and refused connections.
I tried writing them with '\r'
at the end of the string and printed newlines before the other ones started their own output loops thinking the return carriage goes back one line. but they all ended up in the first line overwriting each other.
I've seen similar questions and people were recommending using curses
but i can't seem to get it to work. I try using addstr()
instead of print
or sys.stdout.write()
but clearly i'm not doing it right because it ended up looking like this. I also tried using move(0,0)
after every addstr
because i thought that maybe the coordinates are calculated from the last position of the cursor but the output looked the same as when i didn't do it
Here's my current code using curses
-
from scapy.all import *
from curses import wrapper
import argparse, random, socket, sys, time, os, threading, re, subprocess, curses
def main(target):
try:
stdscr.clear()
curses.noecho()
curses.cbreak()
stdscr.keypad(1)
#things regarding user agents and iptables
for conn in range(args.connections):
t = threading.Thread(target=sendPacket, args=(targetIP, args.port, targetHost,random.choice(userAgents)))
threads.append(t)
t.start()
numConn += 1
try:
lock.acquire()
stdscr.addstr(0, 0,'{0} Connections Established to {1} '.format(numConn,getIP(target)))
stdscr.refresh()
#sys.stdout.flush()
finally:
lock.release()
time.sleep(args.timer)
CloseWin()
sys.exit()
except KeyboardInterrupt, e:
lock.acquire()
stdscr.addstr (5,0,'Exiting {0}'.format(e))
CloseWin()
lock.release()
sys.exit()
#functions that deal with resolving host and IP
def sendPacket(targetIP,targetPort,targetHost,userAgent):
try:
#building and sending the packet
failPacket = 0
lock.acquire()
if synack is None:
stdscr.addstr(1, 0, '{0} Connections refused'.format(failPacket))
stdscr.refresh()
failPacket += 1
return
#send final packet
lock.release()
return
except Exception,e:
CloseWin()
#print e
lock.release()
return
def MeasureTime():
try:
lock.acquire()
while True:
stdscr.addstr(3, 0,'{0} Time elapsed'.format(time.time() - startTime))
stdscr.refresh()
finally:
lock.release()
def CloseWin():
try:
lock.acquire()
curses.nocbreak()
stdscr.keypad(0)
curses.echo()
curses.endwin()
finally:
lock.release()
if __name__ == '__main__':
#args
stdscr = curses.initscr()
if args.debug == True:
wrapper(OneConn(args.target)) #OneConn is the same as the main function except it only opens one connection, so the print is the same
else:
startTime = time.time()
wrapper(main(args.target))
Also in addition to not writing correctly i can't seem to close it properly, when i use ctrl+c
to try and get out it looks like it stops updating the print outs regarding the packet but the time still keeps going. and i can't figure out a way to stop it other than closing the terminal.
Tried adding locks per @martinaeu's suggestion and edited the post to show what i did. And the result was that i can only see the time elapsed
being printed out and updated in the fourth line, can't see the other prints at all and still can't get out of the program without closing the terminal
回答1:
Instead of using curses
, you can simply emit the raw codes to move the cursor back three lines. This would be:
os.write(1, "\x1b[3F")
Be careful: the lines are not erased. It shouldn't be a problem if the new lines that you print have the same length as the old ones (e.g. because they are formatted with something like "foo: %10d"
).
Reference: https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes (where "CSI" stands for "\x1b[" and the n is an optional number written in decimal).
来源:https://stackoverflow.com/questions/47498045/how-to-write-three-constantly-updating-lines-in-terminal-using-curses