How can I do the equivalent of mv in Python?
mv "path/to/current/file.foo" "path/to/new/destination/for/file.foo"
os.rename(), os.replace(), or shutil.move()
All employ the same syntax:
import os
import shutil
os.rename("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
os.replace("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
The filename ("file.foo") must be included in both the source and destination arguments. If it differs between the two, the file will be renamed as well as moved.
The directory within which the new file is being created must already exist.
On Windows, a file with that name must not exist or an exception will be raised, but os.replace() will silently replace a file even in that occurrence.
shutil.move simply calls os.rename in most cases. However, if the destination is on a different disk than the source, it will instead copy and then delete the source file.
Although os.rename() and shutil.move() will both rename files, the command that is closest to the Unix mv command is shutil.move(). The difference is that os.rename() doesn't work if the source and destination are on different disks, while shutil.move() is files disk agnostic.
After Python 3.4, you can also use pathlib's class Path to move file.
from pathlib import Path
Path("path/to/current/file.foo").rename("path/to/new/destination/for/file.foo")
https://docs.python.org/3.4/library/pathlib.html#pathlib.Path.rename
For either the os.rename or shutil.move you will need to import the module.
No * character is necessary to get all the files moved.
We have a folder at /opt/awesome called source with one file named awesome.txt.
in /opt/awesome
○ → ls
source
○ → ls source
awesome.txt
python
>>> source = '/opt/awesome/source'
>>> destination = '/opt/awesome/destination'
>>> import os
>>> os.rename(source, destination)
>>> os.listdir('/opt/awesome')
['destination']
We used os.listdir to see that the folder name in fact changed.
Here's the shutil moving the destination back to source.
>>> import shutil
>>> source = '/opt/awesome/destination'
>>> destination = '/opt/awesome/source'
>>> shutil.move(source, destination)
>>> os.listdir('/opt/awesome/source')
['awesome.txt']
This time I checked inside the source folder to be sure the awesome.txt file I created exists. It is there
Now we have moved a folder and its files from a source to a destination and back again.
This is what I'm using at the moment:
import os, shutil
path = "/volume1/Users/Transfer/"
moveto = "/volume1/Users/Drive_Transfer/"
files = os.listdir(path)
files.sort()
for f in files:
src = path+f
dst = moveto+f
shutil.move(src,dst)
You can also turn this into a function, that accepts a source and destination directory, making the destination folder if it doesn't exist, and moves the files. Also allows for filtering of the src files, for example if you only want to move images, then you use the pattern '*.jpg', by default, it moves everything in the directory
import os, shutil, pathlib, fnmatch
def move_dir(src: str, dst: str, pattern: str = '*'):
if not os.path.isdir(dst):
pathlib.Path(dst).mkdir(parents=True, exist_ok=True)
for f in fnmatch.filter(os.listdir(src), pattern):
shutil.move(os.path.join(src, f), os.path.join(dst, f))
The accepted answer is not the right one, because the question is not about renaming a file into a file, but moving many files into a directory. shutil.move will do the work, but for this purpose os.rename is useless (as stated on comments) because destination must have an explicit file name.
Since you don't care about the return value, you can do
import os
os.system("mv src/* dest/")
Also possible with using subprocess.run() method.
python:
>>> import subprocess
>>> new = "/path/to/destination"
>>> old = "/path/to/new/destination"
>>> process = "mv ..{} ..{}".format(old,new)
>>> subprocess.run(process, shell=True) # do not remember, assign shell value to True.
This will work fine when working on Linux. Windows probably gives error since there is no mv Command.
Based on the answer described here, using subprocess is another option.
Something like this:
subprocess.call("mv %s %s" % (source_files, destination_folder), shell=True)
I am curious to know the pro's and con's of this method compared to shutil. Since in my case I am already using subprocess for other reasons and it seems to work I am inclined to stick with it.
This is dependent on the shell you are running your script in. The mv command is for most Linux shells (bash, sh, etc.), but would also work in a terminal like Git Bash on Windows. For other terminals you would have to change mv to an alternate command.
This is solution, which does not enables shell using mv.
from subprocess import Popen, PIPE, STDOUT
source = "path/to/current/file.foo",
destination = "path/to/new/destination/for/file.foo"
p = Popen(["mv", "-v", source, destination], stdout=PIPE, stderr=STDOUT)
output, _ = p.communicate()
output = output.strip().decode("utf-8")
if p.returncode:
print(f"E: {output}")
else:
print(output)
import os,shutil
current_path = "" ## source path
new_path = "" ## destination path
os.chdir(current_path)
for files in os.listdir():
os.rename(files, new_path+'{}'.format(f))
shutil.move(files, new_path+'{}'.format(f)) ## to move files from
different disk ex. C: --> D:
Related
I have ~60 subdirectories in a single directory. Each of these contain thousands of files, but they all contain a file named test_all_results.txt.
What I would like to do is to rename each test_all_results.txt file so that it now has the name:
foldername_all_results.txt
What is the best way to do this?
Easily accomplished using Python os interface.
Assuming you are currently in the main directory:
import os
#get a list of all sub directories
subdir = os.listdir()
for dir in subdir:
if os.path.isdir(dir): #check if directory
os.chdir(dir) #move to sub directory
os.rename('test_all_results.txt', 'foldername_all_results.txt')
os.chdir('..') #return to main directory
Using python in Linux, make this:
import os
os.system("mv old_name.txt new_name.txt")
You can automatize with a loop, renaming all filenames.
You can do:
(change your code accordingly)
import os
# current directory is the target
direct = "."
for path, dirs, files in os.walk(direct):
for f in files:
if os.path.splitext(f)[0] == "test_all_results.txt":
os.rename(os.path.join(path, f), os.path.join(path, "foldername_all_results.txt"))
There's an answer that tells you to use the os.system() method, if you do decide to call Linux commands from Python, I'd advise that you use the subprocess module instead.
Here's how you'd run the mv command with two arguments using subprocess.call:
import subprocess
subprocess.call(["mv", "filename.txt", "new-name.txt"])
INFO: here's an old (but relevant) article that explains why it's dangerous to use these methods.
Good luck.
I'm trying to do mv test-dir/* ./ but in python. I have written the following code but throws OSError: [Errno 66] Directory not empty:
import os
os.rename(
os.getcwd() + '/test-dir',
os.path.abspath(os.path.expanduser('.')))
You may want to use shutil.move() to iteratively move the files from a directory to another.
For example,
import os
import shutil
from_dir = os.path.join(os.getcwd(),"test-dir")
to_dir = os.path.abspath(os.path.expanduser('.'))
for file in os.listdir(from_dir):
shutil.move(os.path.join(from_dir, file), to_dir)
You're telling the OS to move test-dir, not its contents. It would normally replace the target (. in this case) but that target obviously isn't empty, so the implicit rmdir fails. Even if it weren't empty, it's likely impossible to remove or replace the . name.
The shell * is a glob, which would expand to each thing within test-dir, which you could move individually; however, you'd want to transfer their name to the target directory, i.e. test-dir/foobar to ./foobar. os.path.basename can help you extract that portion.
I have made some python function for compiling passed string as pdf file using latex. The function works as expected and has been quite useful, therefore I look for ways to improve it.
The code which I have:
def generate_pdf(pdfname,table):
"""
Generates the pdf from string
"""
import subprocess
import os
f = open('cover.tex','w')
tex = standalone_latex(table)
f.write(tex)
f.close()
proc=subprocess.Popen(['pdflatex','cover.tex'])
subprocess.Popen(['pdflatex',tex])
proc.communicate()
os.unlink('cover.tex')
os.unlink('cover.log')
os.unlink('cover.aux')
os.rename('cover.pdf',pdfname)
The problem with the code is that it creates bunch of files named cover in the working directory which afterwards are removed.
How to avoid of creating unneeded files at the working directory?
Solution
def generate_pdf(pdfname,tex):
"""
Genertates the pdf from string
"""
import subprocess
import os
import tempfile
import shutil
current = os.getcwd()
temp = tempfile.mkdtemp()
os.chdir(temp)
f = open('cover.tex','w')
f.write(tex)
f.close()
proc=subprocess.Popen(['pdflatex','cover.tex'])
subprocess.Popen(['pdflatex',tex])
proc.communicate()
os.rename('cover.pdf',pdfname)
shutil.copy(pdfname,current)
shutil.rmtree(temp)
Use a temporary directory. Temporary directories are always writable and can be cleared by the operating system after a restart. tempfile library lets you create temporary files and directories in a secure way.
path_to_temporary_directory = tempfile.mkdtemp()
# work on the temporary directory
# ...
# move the necessary files to the destination
shutil.move(source, destination)
# delete the temporary directory (recommended)
shutil.rmtree(path_to_temporary_directory)
I have a file, for example "something.exe" and I want to find path to this file
How can I do this in python?
Perhaps os.path.abspath() would do it:
import os
print os.path.abspath("something.exe")
If your something.exe is not in the current directory, you can pass any relative path and abspath() will resolve it.
use os.path.abspath to get a normalized absolutized version of the pathname
use os.walk to get it's location
import os
exe = 'something.exe'
#if the exe just in current dir
print os.path.abspath(exe)
# output
# D:\python\note\something.exe
#if we need find it first
for root, dirs, files in os.walk(r'D:\python'):
for name in files:
if name == exe:
print os.path.abspath(os.path.join(root, name))
# output
# D:\python\note\something.exe
if you absolutely do not know where it is, the only way is to find it starting from root c:\
import os
for r,d,f in os.walk("c:\\"):
for files in f:
if files == "something.exe":
print os.path.join(r,files)
else, if you know that there are only few places you store you exe, like your system32, then start finding it from there. you can also make use of os.environ["PATH"] if you always put your .exe in one of those directories in your PATH variable.
for p in os.environ["PATH"].split(";"):
for r,d,f in os.walk(p):
for files in f:
if files == "something.exe":
print os.path.join(r,files)
Just to mention, another option to achieve this task could be the subprocess module, to help us execute a command in terminal, like this:
import subprocess
command = "find"
directory = "/Possible/path/"
flag = "-iname"
file = "something.foo"
args = [command, directory, flag, file]
process = subprocess.run(args, stdout=subprocess.PIPE)
path = process.stdout.decode().strip("\n")
print(path)
With this we emulate passing the following command to the Terminal:
find /Posible/path -iname "something.foo".
After that, given that the attribute stdout is binary string, we need to decode it, and remove the trailing "\n" character.
I tested it with the %timeit magic in spyder, and the performance is 0.3 seconds slower than the os.walk() option.
I noted that you are in Windows, so you may search for a command that behaves similar to find in Unix.
Finally, if you have several files with the same name in different directories, the resulting string will contain all of them. In consequence, you need to deal with that appropriately, maybe using regular expressions.
This is really old thread, but might be useful to someone who stumbles across this. In python 3, there is a module called "glob" which takes "egrep" style search strings and returns system appropriate pathing (i.e. Unix\Linux and Windows).
https://docs.python.org/3/library/glob.html
Example usage would be:
results = glob.glob('./**/FILE_NAME')
Then you get a list of matches in the result variable.
Uh... This question is a bit unclear.
What do you mean "have"? Do you have the name of the file? Have you opened it? Is it a file object? Is it a file descriptor? What???
If it's a name, what do you mean with "find"? Do you want to search for the file in a bunch of directories? Or do you know which directory it's in?
If it is a file object, then you must have opened it, reasonably, and then you know the path already, although you can get the filename from fileob.name too.
I'm confused with file moving under python.
Under windows commandline, if i have directory c:\a and a directory c:\b, i can do
move c:\a c:\b
which moves a to b result is directory structure c:\b\a
If I try this with os.rename or shutil.move:
os.rename("c:/a", "c:/b")
I get
WindowsError: [Error 17] Cannot create a file when that file already exists
If I move a single file under c:\a, it works.
In python how do i move a directory to another existing directory?
os.rename("c:/a", "c:/b/a")
is equivalent to
move c:\a c:\b
under windows commandline
You can try using the Shutil module.
os.rename("c:/a/", "c:/b"/) --> Changes the name of folder a in folder b
os.rename("c:/a/", "c:/b/a") --> Put folder b into folder a
When i need many file system operations I prefer using 'path' module:
http://pypi.python.org/pypi/path.py/2.2
It's quite a good and lightweight wrapper around built-in 'os.path' module.
Also code:
last_part = os.path.split(src)[1]
is a bit strange, cause there is special function for this:
last_part = os.path.basename(src)
You will need to state the full path it's being moved to:
src = 'C:\a'
dst_dir = 'C:\b'
last_part = os.path.split(src)[1]
os.rename(src, os.path.join(dst_dir, last_part))
Actually, it looks like shutil.move will do what you want by looking at its documentation:
If the destination is a directory or a symlink to a directory, the
source
is moved inside the directory.
(And its source.)
Using Twisted's FilePath:
from twisted.python.filepath import FilePath
FilePath("c:/a").moveTo(FilePath("c:/b/a"))
or, more generally:
from twisted.python.filepath import FilePath
def moveToExistingDir(fileOrDir, existingDir):
fileOrDir.moveTo(existingDir.child(fileOrDir.basename()))
moveToExistingDir(FilePath("c:/a"), FilePath("c:/b"))