21

I have

cmd = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
for line in cmd.stdout:
  columns = line.split(' ')
  print (columns[3])

have error in line 3 Type Str doesnt support the buffer API.

What am i doing wrong i am on Python 3.3

3 Answers 3

21

You are reading binary data, not str, so you need to decode the output first. If you set the universal_newlines argument to True, then stdout is automatically decoded using the result of the locale.getpreferredencoding() method (same as for opening text files):

cmd = subprocess.Popen(
    'dir', shell=True, stdout=subprocess.PIPE, universal_newlines=True)
for line in cmd.stdout:
    columns = line.decode().split()
    if columns:
        print(columns[-1])

If you use Python 3.6 or newer, you can use an explicit encoding argument for to the Popen() call to specify a different codec to use, like, for example, UTF-8:

cmd = subprocess.Popen(
    'dir', shell=True, stdout=subprocess.PIPE, encoding='utf8')
for line in cmd.stdout:
    columns = line.split()
    if columns:
        print(columns[-1])

If you need to use a different codec in Python 3.5 or earlier, don't use universal_newlines, just decode text from bytes explicitly.

You were trying to split a bytes value using a str argument:

>>> b'one two'.split(' ')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Type str doesn't support the buffer API

By decoding you avoid that problem, and your print() call will not have to prepend the output with b'..' either.

However, you probably just want to use the os module instead to get filesystem information:

import os

for filename in os.listdir('.'):
    print(filename)
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks it works but any idea why i am getting list index out of range error
@NickLoach: the line has fewer than 3 columns?
Thanks Martijn the line has ['03-04-2013', '', '19:48', '', '', '', '<DIR>', '', '', '', '', '', '', '', '', '', '.ipython\r\n'] i want the feild called .ipython as output
Why not use os.listdir() instead?
I made a simple example the command i would be running will not be a os command but a binary that outputs something on the above lines
|
4

A simpler solution of the first part of Martijn Pieters's answer is to pass the universal_newlines=True argument to the Popen call.

I would even simplify this to:

output = subprocess.check_output('dir', universal_newlines=True)
columns = output.split()
print(columns)

NOTE: If file or directory names contain spaces, use os.listdir('.') as suggested in Martijn Pieters's answer or something like the following:

output = subprocess.check_output('dir', universal_newlines=True)
columns = []
for e in output.split():
    if len(columns) > 0 and columns[-1].endswith('\\'):
        columns[-1] = columns[-1][:-1] + " " + e
    else:
        columns.append(e)
print(columns)

4 Comments

dir is an internal command on Windows i.e., if there is no dir.exe then shell=True is necessary in this case.
If we assume one-column output then you could use .splitlines(), to handle paths with spaces
@J.F.Sebastian, agreed. I didn't use .splitlines() since my version of dir (GNU coreutils) 8.21 produces output in multiple columns.
dir produces a single column output if stdout is redirected (as it is the case with stdout=PIPE). Try dir | cat, to see it in the terminal
0

Better use binascii.b2a_uu that converts binary data to a line of ASCII characters

from binascii import b2a_uu 
cmd = b2a_uu(subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE))

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.