Reputation: 44385
In python (3.6.8) you can use subprocess.check_call
to run a command, for example
import subprocess
subprocess.check_call("ls -l /home/user".split())
which, in the example, prints out the content of the home directory:
...
drwx------ 25 user user 4096 Jan 27 16:31 Music
-rw-r--r-- 1 user user 0 Jul 9 11:06 nse.file.zip
-rw-rw-r-- 1 user user 1938520956 Jul 8 16:59 nse.file.zip.1
-rw------- 1 user user 514916418 Jul 9 11:15 nse.file.zip.part
drwxr-xr-x 5 user user 12288 Mar 11 14:32 Pictures
drwxr-xr-x 8 user user 4096 Mar 9 06:36 Private
drwxr-xr-x 2 user user 4096 Jul 30 2018 Public
...
But, in contrast, when you want to use placeholders to list several files at once, this does not seem to work anymore:
subprocess.check_call("ls -l /home/user/nse*".split())
or
subprocess.check_call("ls -l '/home/user/nse*'".split())
In both cases I get an error
CalledProcessError: Command '['ls', '-l', '/home/user/nse*']' returned non-zero exit status 2.
or
CalledProcessError: Command '['ls', '-l', "'/home/user/nse*'"]' returned non-zero exit status 2.
What am I missing? How to fix this issue?
Upvotes: 1
Views: 460
Reputation: 2035
You are missing the fact that wildcard expansion (understanding what *
means) is not done by ls
but it is done by shell. When you run something like ls a*.b
in shell, it's shell who finds out what are a*.b
files, and then passes them to ls
. Now you're asking ls
: give me the file named nse*
literally. There's no such file, of course.
You can use subprocess.check_call(..., shell=True)
to run the command through shell (which will do wildcard expansion before calling the command).
See:
>>> subprocess.check_call("ls /tmp/foo*".split())
ls: cannot access '/tmp/foo*': No such file or directory
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.7/subprocess.py", line 347, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['ls', '/tmp/foo*']' returned non-zero exit status 2.
>>> subprocess.check_call("ls /tmp/foo*", shell=True)
/tmp/foo.bar /tmp/foo.c
0
Notice no .split()
in the second case -- the whole string is given as an argument to a shell.
Upvotes: 2
Reputation: 41188
You can do:
subprocess.check_call("ls -l /home/user/nse*", shell=True)
Upvotes: 2