4

I am writing a Python 2 program to find a file. This program should print each directory it searches at each iteration of the search, but always to the same line in the terminal (i.e. by erasing the text that is already there and moving the cursor to the beginning of the line before printing again.)

This is the code I have so far:

import os
import sys
for root, dirs, files in os.walk("/"):
    print root +'\r',
    print '\x1b[2K\r',

My problem is that it starts each printout (when it change directory) on a new line; in other words, it doesn't reuse the old line.

How can I ensure all printed output goes to a single line in the terminal?

9
  • @thebjorn i will correct the question. Commented Aug 14, 2015 at 10:11
  • @thebjorn I tried providing an edit that's hopefully more legible. Commented Aug 14, 2015 at 10:13
  • @thebjorn thanks sir. Commented Aug 14, 2015 at 10:14
  • @PeterWood i changed it to sys.stdout.write( '\x1b[2K\r' + root ,) but same result. Commented Aug 14, 2015 at 10:17
  • @PeterWood not true, the comma he added at the end of the line prevents print from going to a new line. Commented Aug 14, 2015 at 10:17

4 Answers 4

2

You need to flush the stdout buffer (depends on the terminal system), and pad the line with whitespace. For example:

for root, dirs, files in os.walk(path):
    print "%-80s\r" % (root),
    sys.stdout.flush()
    time.sleep(1)    # For testing

This assumes an arbitrary maximum filename length of 80 characters.

EDIT:

This new solution uses curses, which is part of the standard library:

import curses
import os
import time

win = curses.initscr()

for root, dirs, files in os.walk(path):
    win.clear()
    win.addstr(0, 0, root)
    win.refresh()
    time.sleep(1)     # For testing purposes

curses.endwin()
Sign up to request clarification or add additional context in comments.

7 Comments

It generate new line.
@chosipa it really doesn't. (I've tried linux, dos, and ConEmu, all work as expected).
I did test with sys.stdout.write("%-80s\r" % root). The only place I could see this not working is if you're running in IDLE or something else that grabs sys.stdout (haven't tested it though).
The issue might be if you have a path length which exceeds the width of the terminal line, typically 80 chars. You could truncate the displayed line? By "pc" do I take that to mean you are using Microsoft's Windows?
NO i am using Ubuntu, I think it is character length that push it in new line, how can i fix it ?
|
1

This should do it.

for root, dirs, files in os.walk(path):
    print '\r', root,

The \r tells python to rewind to the beginning of the current line, like old typewriters.

You might want to pad with spaces to erase the rest of the line, if the current path is shorter than the previous path.

If the text is longer than one line, it will still overflow to the next line.

2 Comments

It gave me the same result.
no way, same result, replace path with "/" and test it on your pc.
1

You need to shorten your output to under the terminal limit.

You could just truncate and put ellipsis at the front:

limit = 30  # for example
message = 'ABCDEFGHIJKLMNOPQRSTUVWX' * 4
if len(message) > limit:
    message = '...' + message[-limit+3:]
print message  # ...VWXABCDEFGHIJKLMNOPQRSTUVWX

If you want to replace the middle with ..., then you could do:

limit = 30  # for example
message = 'ABCDEFGHIJKLMNOPQRSTUVWX' * 4
length = len(message)  # will be 100
if length > limit:
    message = list(message)
    cut_size = length - limit
    start_cut = (length - cut_size) / 2
    message[start_cut:start_cut + cut_size + 3] = '...'
    message = ''.join(message)

print message  # ABCDEFGHIJKLMNO...MNOPQRSTUVWX

Comments

0

Inspired by several ideas from here and there, this works for me well:

import os
import sys
import time # only if you use sleep() function for debugging

top_folder = "/"
max_line_length = 80


for root, dirs, files in os.walk(top_folder):

    message = root

    # truncate if the path longer than what you want it to be
    if len(message) > max_line_length:
        message = '[...]' + message[-max_line_length+5:]

    # prepare the output string of lenght determined by a variable
    output_string = '{0: <' + str(max_line_length) + '}\r' # \r = carret return

    # output
    print output_string.format(message), # the comma is crucial here

    # to see it in action in slow-motion
    time.sleep(.4)

The last 2 code lines before the sleep() function line could be combined into one line:

print '{msg: <{width}}\r'.format(msge = message, width = max_line_length),

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.