2

In the linux terminal i can delete all files from directory including hidden ones with:

sudo rm -rf /path/to/folder/{*,.*} 2> /dev/null

I'm trying to run the following command via os.system in python:

>>> os.system('sudo rm -rf /path/to/folder/{*,.*}')

this will exit without any error (exit code 0) but do not delete nothing.

I understand here probably the curly braces have a special meaning but trying \{*,.*\} will not change nothing.

Wondering what going one here and how to tell python to use the Curly braces as in the terminal.

Of corse to make the job done i can do:

os.system('sudo rm -r /path/to/folder/* /path/to/folder/.myHiddenFile')  # or other combination

But i want to understand how to play with the Curly braces here.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Zorro
  • 1,085
  • 12
  • 19
  • 1
    I suspect the braces are being expanded by the terminal itself *before* being passed to rm, while executing the command this way will pass them directly to rm. – Kemp Apr 08 '21 at 14:13
  • interresting theorie... – Zorro Apr 08 '21 at 14:16
  • @Kemp exactly that is the case – TheEagle Apr 08 '21 at 14:18
  • Related: [os.system() execute command under which linux shell?](https://stackoverflow.com/q/905221/4518341) General question: [How to execute a program or call a system command from Python](https://stackoverflow.com/q/89228/4518341) – wjandrea Apr 08 '21 at 14:33

3 Answers3

6

os.system calls the C standard library function system, which executes the command with /bin/sh -c.

Since the curly brace expansion you are using is a bash feature, the underlying shell that os.system is using simply does not understand.

To workaround, you can explicitly execute the command in bash by invoking /bin/bash (or whereever your bash is) with the -c argument. E.g.

os.system("/bin/bash -c 'sudo rm -rf /path/to/folder/{*,.*}'")

NOTE: the use of single quotes, which are needed because of sudo.

L.Grozinger
  • 2,280
  • 1
  • 11
  • 22
2

os just helps you make a subset of OS-related system calls. The curly brace expansion you are describing is not an OS-related feature, it's a bash idiom. I doubt it is available even in other (non-bash) shells, as a rule.

The bash curly brace feature parses your curly brace expression and uses rules to turn it into more verbose expressions. You can read more about it here as well as other places on the internet if you google "bash curly braces".

If you want to do something similar to what bash curly braces do on files, check out the python library glob. If you want to do something similar to what bash curly braces do on text or on numbers, you can look at itertools maybe. (Or, in all these cases, maybe you really just want to write a simple for loop.)

sinback
  • 926
  • 5
  • 17
2

os.system does not do shell expansion. This means the curly braces are left as they are, and not replaced as you are used to it from in the terminal. To get this feature, you can use subprocess.run with shell=True:

import subprocess, shlex

result = subprocess.run(shlex.split("sudo rm -rf /path/to/folder/{*,.*}"), shell=True) # shlex.split converts the string into an argument list

print("rm exited with exit code %s, and printed following output\n%s\n and following errors\n%s\n" % (result.exitcode, result.stdout, result.stderr))
TheEagle
  • 5,808
  • 3
  • 11
  • 39