views:

188

answers:

7

I was wondering whether or not it is considered a good style to call bash commands within a Python script using os.system(). I was also wondering whether or not it is safe to do so as well.

I know how to implement some of the functionality I need in Bash and in Python, but it is much simpler and more intuitive to implement it in Bash. However, I feel like it is very hackish to write os.system("bash code").

Specifically, I want to move all files that end with a certain extension to a directory.

In bash: *mv .ext /path/to/destination In Python (Pseudocode): for file in directory: if file.endswith("ext"): move file to destination

In this case, what should I do?

+3  A: 

It always better and better style to use Python functions to do this kind of stuff. With Python it's not that hard to write a script in an OS-independent way instead of using bash.

Steven Mohr
+1  A: 

It's not idea, since it makes your script a lot less portable. A native python script can run on any unix or windows machine that has the proper python libraries installed. When you add shell commands into the mix, you break that, and suddenly are locked down to a much narrower subset.

Sometimes you don't have a choice, but if it's something as simple as that, writing the code natively in python would make a lot more sense, and also be faster to boot (since the python process won't have to spawn a new shell just to execute the one command).

zigdon
+6  A: 

Check out Python's shutil module. It offers file system operations such as moving files. Between that and the os module, you should have all the tools you need. This is preferable to the bash commands for the reasons others said.

Rob Lourens
+1  A: 

The quoting issues alone suggest that a pure Python solution is preferable.

ndim
+2  A: 

Some reasons why you should use pure Python,

  1. By using Python, you have already made the assumption that Python and the standard libraries are installed. By using Bash code inside of Python you are making this assumption plus the assumption that Bash is installed and on the system path.
  2. By using a combination of two languages you are making the code more difficult for others to read (not everyone knows Python and Bash)
  3. If you do it the Python way it will feel more natural before long - less lines of code is not always better

In this case, I would use ...

import os
for filename in os.listdir('.'):
  if filename.endswith('.ext'):
    os.rename(filename, os.path.join('path', 'to', 'new', 'destination', filename))

There may be better ways though

Brendan
You could do away with the file.endswith() if you'd use glob.glob('*.ext') instead of os.listdir
Mattias Nilsson
+7  A: 

First of all, your example uses mv, which is a program in coreutils, not bash.

Using os.system() calls to external programs is considered poor style because:

  • You are creating platform-specific dependencies
  • You are creating version-specific dependencies (Yes, even coreutils change sometimes!)
  • You need to check for the existence of external commands (and that they are in $PATH, and executable by the user etc.)
  • You have to wrap the commands with error checking using their return code. It is much nicer to use in-language error-codes or exceptions. (os.system() does not let you parse stdout/stderr)
  • You have to deal with quoting variables with spaces yourself (or escaping them)
  • Python has already done the work for you by supplying the libraries!

Look up glob, for shell-like pattern matching (globbing), and shutil, as others have already mentioned. Otherwise, everything you need is already in the standard libraries.

import glob
import shutil

for extfile in glob.glob('*.ext'):
    shutil.move(extfile,dest)  

In addition, os.system() should not be used - take a look at the subprocess module instead.

James Broadhead
Good answer, but I cringe a little when I see variables named "file" since it hides the built in file.
Mattias Nilsson
Good comment - edited :)
James Broadhead
Great answer, but for those looking for more bash->python migration info I'll link to http://stackoverflow.com/questions/209470/can-i-use-python-as-a-bash-replacement
Nickolay
A: 

More generally, Python provides the 'subprocess' module that will allow you to run commands and exercise extensive control over their output. It lets you "spawn new processes, connect to their input/output/error pipes, and obtain their return codes":

http://docs.python.org/library/subprocess.html

Marc Alvidrez