Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the mv command in Python with subprocess

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.

like image 791
CSStudent Avatar asked Feb 15 '14 23:02

CSStudent


People also ask

How do you run a command in subprocess in Python?

Running a Command with subprocess In the first line, we import the subprocess module, which is part of the Python standard library. We then use the subprocess. run() function to execute the command.

How do you use mv?

Use the mv command to move files and directories from one directory to another or to rename a file or directory. If you move a file or directory to a new directory without specifying a new name, it retains its original name. Attention: The mv command can overwrite many existing files unless you specify the -i flag.

What is the use of subprocess Popen in Python?

The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.

What is shell in subprocess?

Setting the shell argument to a true value causes subprocess to spawn an intermediate shell process, and tell it to run the command. In other words, using an intermediate shell means that variables, glob patterns, and other special shell features in the command string are processed before the command is run.


3 Answers

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.

like image 112
zmo Avatar answered Oct 02 '22 15:10

zmo


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.

like image 34
Maxime Lorant Avatar answered Oct 02 '22 17:10

Maxime Lorant


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.

like image 44
jpaugh Avatar answered Oct 02 '22 16:10

jpaugh