How to use the mv command in Python with subprocess

15,068

Solution 1

if you call subprocess that way:

subprocess.call(["mv", "/home/somedir/subdir/*", "somedir/"])

you're actually giving the argument /home/somedir/subdir/* to the mv command, with an actual * file. i.e. you're actually trying to move the * file.

subprocess.call("mv /home/somedir/subdir/* somedir/", shell=True)

it will use the shell that will expand the first argument.

Nota Bene: when using the shell=True argument you need to change your argument list into a string that will be given to the shell.

Hint: You can also use the os.rename() or shutil.move() functions, along with os.path.walk() or os.listdir() to move the files to destination in a more pythonic way.

Solution 2

You can solve this by adding the parameter shell=True, to take into account wildcards in your case (and so write the command directly, without any list):

subprocess.call("mv /home/somedir/subdir/* somedir/", shell=True)

Without it, the argument is directly given to the mv command with the asterisk. It's the shell job to return every files which match the pattern in general.

Solution 3

You are using shell globbing *, and expecting the mv command to know what it means. You can get the same error from a command shell this way:

$ mv 'somedir/subdir/*' ...

Notice the quotes. The shell usually does glob-matching on * for you, but commands don't do that on their command lines; not even a shell does. There is a C library function called fnmatch that does shell-style globbing for you, which every programming language more or less copies. It might even have the same name in Python. Or it might have the word "glob" in it; I don't remember.

Share:
15,068

Related videos on Youtube

CSStudent
Author by

CSStudent

Updated on June 04, 2022

Comments

  • CSStudent
    CSStudent almost 2 years

    I have a lot of files in /home/somedir/subdir/ and I'm trying to move them all up to /home/somedir programmatically.

    right now I have this:

    subprocess.call(["mv", "/home/somedir/subdir/*", "somedir/"])
    

    but it's giving me this error:

    mv: cannot stat `/home/somedir/subdir/*': No such file or directory
    

    I know that it does exist because when I type the mv command by hand using the exact same command as the script uses it works perfectly.

  • zmo
    zmo about 10 years
    your example does actually work the shell expands inside double quotes, you should use single quotes to make a point.
  • jpaugh
    jpaugh about 10 years
    Oh, that's right. What's really fun is the way (ba)sh handles single quotes inside of double quotes. It can get pretty hairy when you stash it in a var and then try to splice it into a command line!
  • jpaugh
    jpaugh about 10 years
    +2 For Pythonic idiom; otherwise, one may as well use the shell!
  • John1024
    John1024 over 3 years
    While this does escape blanks, there are other characters of concern. Tabs, newlines, and single quotes are all valid characters in filenames and would need special attention.