0

I'm trying to run a bash command with Python3 on Ubuntu. Here is the code (sc.py)

import subprocess
path = '/home/user2/*'
result = subprocess.run(['ls', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
print(result.stdout.decode("utf-8"))
print(result.stderr.decode("utf-8"))

Both python3 sc.py and sudo python3 sc.py give

ls: cannot access '/home/u0502210301/*': No such file or directory

However, directly running the command ls /home/user2/* with bash outputs as expected.

All the tests above are run with a sudo account user1.

Could someone give me a hint about this?

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
JJJohn
  • 915
  • 8
  • 26
  • If `ls` is the actual command, there are better alternatives than using `subprocess` at all. If `ls` isn't the actual command, there *may* be better alternatives. – chepner Dec 28 '21 at 23:17
  • 1
    `*` has no meaning to `ls` itself; ls depends on the _shell_ to replace `/home/user2/*` with a list of individual names like `/home/user2/a.txt` `/home/user2/b.txt` etc. You have no shell, so nothing is doing that replacement, so `ls` is looking for a file named `*`, which doesn't exist, hence your error. – Charles Duffy Dec 28 '21 at 23:17
  • 3
    Wildcard expansion (the `*` at the end of your path) is done by a shell, but you're implicitly running the command with `shell-False`. Are you trying to get a list of matching files? If so, [don't try to parse `ls`](https://mywiki.wooledge.org/ParsingLs), use [something native to Python like glob.glob](https://stackoverflow.com/questions/3348753/search-for-a-file-using-a-wildcard). – Gordon Davisson Dec 28 '21 at 23:20
  • @GordonDavisson, ...the duplicate you added is in and of itself a good one, but the sole answer (as of this writing) leaves something to be desired; `shell=True` is more a last resort than a first choice. – Charles Duffy Dec 28 '21 at 23:56
  • @CharlesDuffy On the other hand, I apparently inspired you to add a better answer! – Gordon Davisson Dec 29 '21 at 02:20

2 Answers2

2

The path does not expand globbing * so this is invalid:

path = '/home/user2/*'

Instead do this with expanding the glob into arguments entries to the ls command:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import subprocess
import glob

globPath = '/home/user2/*'
result = subprocess.run(['ls'] + glob.glob(globPath), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
print(result.stdout.decode("utf-8"))
print(result.stderr.decode("utf-8"))
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
1

This has to do with glob expansion. You are expecting * to be handled in python subprocess run as it would be in bash, but that is not the case. To solve the "not found" problem, you can just remove the /* and replace it with /, so:

import subprocess
path = '/home/user2/'
result = subprocess.run(['ls', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
print(result.stdout.decode("utf-8"))
print(result.stderr.decode("utf-8"))

this will solve part of the problem, but may not work for your use case (if you want to list all the files/divs in the subdirectories of user2)

Here's a solution which will work for your exact case, I believe:

import subprocess
import glob
path = '/home/user2/*'
cmd = ['ls']
cmd.extend(glob.glob(path))
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(result.stdout.decode("utf-8"))
print(result.stderr.decode("utf-8"))
Sean
  • 91
  • 1
  • 6
  • I was in the process of writing a solution to their problem. Besides, they were asking for hints in their original post. We're all just trying our best, man. – Sean Dec 28 '21 at 23:19
  • Sure, but the goal here is to create a teaching resource. That means part of trying our best is to provide useful critique so readers can understand the limitations of each answer they're given, or so those answers can be refined or improved. – Charles Duffy Dec 28 '21 at 23:20
  • It seems to me like you did a quite good job of improving the answer following the comment in question (making the comment no longer necessary or relevant, hence its deletion). I still prefer the other answer insofar as it avoids showing an approach that's only good for `ls`, but that's personal preference (hence an upvote there) rather than an assertion that anything in this one is objectively bad. – Charles Duffy Dec 28 '21 at 23:59