Gio
Gio

Reputation: 3340

Execute the command "ls -d */" with subprocess.Popen vs. os.popen

On Linux OS, the python code below provides the directories inside the current directory.

dirs = os.popen('ls -d */').read().split(os.linesep)
print dirs

Because os.popen is deprecated, I'm migrating this call to subprocess.Popen

proc = subprocess.Popen(['ls', '-d', '*/'], stdout=subprocess.PIPE)
outp = proc.stdout.read()
print outp

However for some reason this doesn't work, I get the following error

ls: cannot access */: No such file or directory

Upvotes: 1

Views: 1323

Answers (1)

ShadowRanger
ShadowRanger

Reputation: 155506

*/ only works if globbing is being performed; in os.popen, the whole string is being evaluated by a shell which is wrapping the actual ls process, and the shell is performing the expansion. When you use the list based Popen, it's passing the literal string */ to ls, and ls doesn't expand globs on its own.

You could pass a str and shell=True to Popen, but that's just reopening the performance, security and stability holes that os.popen has. Easier is to avoid subprocesses at all, just use the glob module or one of os.listdir/os.scandir/os.walk instead of using subprocesses at all.

For example, in Python 3.5 with os.scandir, you can get all the directories in the working directory extremely efficiently with:

import os

dirs = [x.name for x in os.scandir() if x.is_dir()]

On earlier versions of Python, os.listdir + os.path.isdir can be used to do the same thing slightly less efficiently (it involves a stat of each entry which os.scandir can avoid, but for small directories and/or local filesystems, the stat cost is trivial):

import os, os.path

dirs = [f for f in os.listdir('.') if os.path.isdir(f)]

Upvotes: 4

Related Questions