Issue
I'm trying to figure out how to run this command using subprocess.run()
:
cmd = 'find / \( -path /mnt -prune -o -path /dev -prune -o -path /proc -prune -o -path /sys -prune \) -o ! -type l -type f -or -type d -printf "depth="%d/"perm="%m/"size="%s/"atime="%A@/"mtime"=%T@/"ctime"=%C@/"hardlinks"=%n/"selinux_context"=%Z/"user="%u/"group="%g/"name="%p/"type="%Y\\n'
I've put the command into a list, even removing items, etc:
cmd = [
'find',
'/',
'\( -path /mnt -prune -o -path /dev -prune -o -path /proc -prune -o -path /sys -prune \)',
'-o',
'! -type l',
'-type f',
'-or',
'-type d'
]
I've tried running the command using /bin/bash
:
cmd = '/bin/bash -c find / \( -path /mnt -prune -o -path /dev -prune -o -path /proc -prune -o -path /sys -prune \) -o ! -type l -type f -or -type d -printf "depth="%d/"perm="%m/"size="%s/"atime="%A@/"mtime"=%T@/"ctime"=%C@/"hardlinks"=%n/"selinux_context"=%Z/"user="%u/"group="%g/"name="%p/"type="%Y\\n'
Doesn't matter. Everything I've tried does not work. Either I get no output at all, or it lists the files in my home directory, or I get an error, e.g.: b'find: paths must precede expression: ! -type l\nUsage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]\n'
Is there any easy way to take a command that works at the command line and just parse the string into whatever list elements subprocess.run()
wants?
Solution
Parsing With shlex.split()
After fixing the incorrect quotes in your printf string, we get:
cmd = r'''
find / \( -path /mnt -prune -o -path /dev -prune -o -path /proc -prune -o -path /sys -prune \) -o ! -type l -type f -or -type d -printf 'depth=%d/perm=%m/size=%s/atime=%A@/mtime=%T@/ctime=%C@/hardlinks=%n/selinux_context=%Z/user=%u/group=%g/name=%p/type=%Y\\n'
'''
print(shlex.split(cmd))
...which emits an entirely correct result, and subprocess.call()
works with it properly.
Building A Correct Command Line By Hand
In terms of what it looks like to do this by hand:
cmd = [
'find', '/',
'(',
'-path', '/mnt', '-prune',
'-o', '-path', '/dev', '-prune',
'-o', '-path', '/proc', '-prune',
'-o', '-path', '/sys', '-prune',
')',
'-o', '!', '-type', 'l',
'-type', 'f',
'-or',
'-type', 'd',
'-printf', 'depth=%d/perm=%m/size=%s/atime=%A@/mtime=%T@/ctime=%C@/hardlinks=%n/selinux_context=%Z/user=%u/group=%g/name=%p/type=%Y\n'
]
Note:
- Syntactic quotes change the shell's parsing mode, they don't become part of the data.
"foo"
just becomesfoo
;"foo"bar"baz"
becomesfoobarbaz
. So you can't/shouldn't/don't try to put those quotes into the data that Python is passing in. - This is true also for
\(
: the backslash is shell syntax. It doesn't actually become one offind
's arguments, so you leave it out. - Any space that isn't quoted or escaped separates words; so
-type f
in shell is'-type', 'f'
, two separate words.
Answered By - Charles Duffy Answer Checked By - David Goodson (WPSolving Volunteer)