15

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.

CSStudent
  • 425
  • 1
  • 6
  • 14
  • possible duplicate of [Calling rm from subprocess using wildcards does not remove the files](http://stackoverflow.com/questions/11025784/calling-rm-from-subprocess-using-wildcards-does-not-remove-the-files) – Maxime Lorant Feb 15 '14 at 23:14
  • it's close, but imho not a duplicate, as the other is using `Popen` and has a more complex example. – zmo Feb 15 '14 at 23:15
  • Well, the problem and solution idea are very close. I've already seen some close votes less obvious than that... – Maxime Lorant Feb 15 '14 at 23:17
  • I think it is a dup—it's the same actual problem, with the same actual solution. This question serves as a much better example of the problem, but that doesn't mean it's a different problem. – abarnert Feb 16 '14 at 00:00

4 Answers4

21

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.

zmo
  • 24,463
  • 4
  • 54
  • 90
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.

Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97
2

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.

jpaugh
  • 6,634
  • 4
  • 38
  • 90
  • 2
    your example does actually work the shell expands inside double quotes, you should use single quotes to make a point. – zmo Feb 15 '14 at 23:14
  • 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 Feb 15 '14 at 23:17
0

Here's a simple way to work with subprocess Popen

import subprocess
import os

class FolderCommands:
    src = None
    dst = None

    def __init__(self, src, dst):
        self.src = src
        self.dst = dst

    def move(self):
        listOfFiles = os.listdir(self.src)
        print(listOfFiles)
        modify_src = self.src.replace(" ", "\ ")
        dst = self.dst.replace(" ", "\ ")
        for f in listOfFiles:
            #Attaching the filename at the end of the src path

            fullPath = modify_src + "/'" + f +"'"
            subprocess.Popen("mv" + " " + fullPath + " " + dst, shell=True)

obj = FolderCommands(input("Enter Source path"), input("Enter Destination path"))
obj.move()
kalehmann
  • 4,821
  • 6
  • 26
  • 36
Niketan
  • 54
  • 3
  • 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. – John1024 Aug 23 '20 at 20:01