Reputation: 35
I am currently converting a bash script to python and there is a command in bash : mv -i
I know mv
means MOVE but I'm not sure how to use mv -i
in Python. I tried man move
as well but couldn't understand it well.
Upvotes: 0
Views: 1346
Reputation: 366003
Normally, you wouldn't want to "use mv -i
in Python"; you'd want to use commands in os
or shutil
to do things natively.
But if you do want to use mv -i
, you do it the same way as anything else:
subprocess.check_call(['mv', '-i', srcpath, dstpath])
Keep in mind that the whole point of -i
is that it's interactive. Quoting from the BSD man page:
Cause mv to write a prompt to standard error before moving a file that would overwrite an existing file. If the response from the standard input begins with the character
y' or
Y', the move is attempted.
So, you'd probably want to either let its stdin and stdout pass through, so the user can interact with it directly. Unless you want to, say, pop up a GUI alert instead of a console prompt, in which case you'll have to attach pipes and process things manually, which will not be fun.
If you just want to write native Python code that's "basically the same" as mv -i
, that's not too hard:
if os.path.isfile(dstname):
yesno = input("'{}' already exists. Replace? ".format(dstpath))
if yesno.upper()[0] != 'Y':
raise FileExistsError("'{}': already exists".format(dstpath))
shutil.move(srcpath, dstpath)
However, this isn't exactly the same. Most seriously, it has a race condition that the real command doesn't have (if you move a different file to dstname
between the isfile
call and the move
call, it will get overwritten). But there are also all kinds of trivial differences, like the fact that it doesn't handle the case of moving multiple source files.
If you want to exactly reproduce the behavior of mv -i
in native Python, it would go something like this:
fd = -1
try:
try:
fd = os.open(dstpath, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
except OSError as e:
if e.errno == errno.EEXIST:
yesno = input("'{}' already exists. Replace? ".format(dstpath))
if yesno.upper()[0] != 'Y': raise e
os.rename(srcpath, dstpath)
finally:
if fd > 0: os.close(fd)
Except that you also need code to handle the case where dstpath
is a directory, so you're also going to want to add an fstat
in there, and… Really, you'd want to read the source to an open source implementation of mv
in C, rather than guessing.
More importantly, why do you want to do an mv -i
in the first place? If you look at what your program is actually doing, and what the user experience is supposed to be, there's a good chance this isn't the right answer.
For example, if you ask the user for a filename to save your data into, you could write your data to a tempfile and then mv -i
it to the user's filename… but the user may prefer to verify the overwrite immediately, rather than having to wait until you've already generated the tempfile (especially if that takes a long time).
Upvotes: 5