Home > OS >  python subprocess.run with tar excluded issue
python subprocess.run with tar excluded issue

Time:12-10

I have one issue with subprocess.run.

This command from bash works without any problem: tar -C '/home/' --exclude={'/home/user1/.cache','/home/user1/.config'} -caf '/transito/user1.tar' '/home/user1' > /dev/null 2>&1

but if I execute it trough: cmd = "tar -C '/home/' --exclude={'/home/user1/.cache','/home/user1/.config'} -caf '/transito/user1.tar' '/home/user1' > /dev/null 2>&1" subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)

the execution works without errors but the --exclude clause is not considered.

WHy?

CodePudding user response:

Bash curly expansion doesn't work inside Python and will be sent by subprocess as they are - they will not be expanded, regardless of the arguments you use on run().

In a bash shell,

--exclude {'/home/user1/.cache','/home/user1/.config'}

becomes:

--exclude=/home/user1/.cache --exclude=/home/user1/.config

So to achieve the same result, in Python it must be expressed like this (one of the possible ways) before sending the command string to subprocess.run:

' '.join(["--exclude="   path for path in ['/home/user1/.cache','/home/user1/.config']])
cmd = "tar -C '/home/' "   ' '.join(["--exclude="   path for path in ['/home/user1/.cache','/home/user1/.config']])   " -caf '/transito/user1.tar' '/home/user1' > /dev/null 2>&1"
print(cmd) # output: "tar -C '/home/' --exclude=/home/user1/.cache --exclude=/home/user1/.config -caf '/transito/user1.tar' '/home/user1' > /dev/null 2>&1"
subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)

CodePudding user response:

Whether or not curly brace expansion is handled correctly depends on what the standard system shell is. By default, subprocess.run() invokes /bin/sh. On systems like Linux, /bin/sh is bash. On others, such as FreeBSD, it's a different shell that doesn't support brace expansion.

To ensure the subprocess runs with a shell that can handle braces properly, you can tell subprocess.run() what shell to use with the executable argument:

subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, executable='/bin/bash')

As a simple example of this, here's a system where /bin/sh is bash:

>>> subprocess.run("echo foo={a,b}", shell=True)
foo=a foo=b

and one where it's not:

>>> subprocess.run("echo foo={a,b}", shell=True)
foo={a,b}

but specifying another shell works:

>>> subprocess.run("echo foo={a,b}", shell=True, executable='/usr/pkg/bin/bash')
foo=a foo=b
  • Related