我目前正在将 bash 脚本转换为 python,并且 bash 中有一个命令:mv -i
我知道mv
意味着 MOVE,但我不确定如何mv -i
在 Python 中使用。我也试过man move
,但不能很好地理解它。
1 回答
通常,您不想“mv -i
在 Python 中使用”;您想在其中使用命令os
或shutil
以本机方式执行操作。
但是,如果您确实想使用mv -i
,则使用与其他任何方法相同的方法:
subprocess.check_call(['mv', '-i', srcpath, dstpath])
请记住,它的全部意义-i
在于它是交互式的。引用 BSD 手册页:
导致 mv 在移动将覆盖现有文件的文件之前写入标准错误提示。如果标准输入的响应以字符
y' or
Y' 开头,则尝试移动。
所以,你可能想让它的标准输入和标准输出通过,这样用户就可以直接与之交互。除非您想弹出一个 GUI 警报而不是控制台提示,在这种情况下,您必须手动附加管道并处理事物,这不会很有趣。
如果您只是想编写与“基本相同”的本机 Python 代码mv -i
,那并不太难:
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)
然而,这并不完全相同。最严重的是,它有一个真正的命令没有的竞争条件(如果你在调用和调用dstname
之间移动不同的文件,它将被覆盖)。但是也有各种细微的差别,比如它不能处理移动多个源文件的情况。isfile
move
如果你想准确地重现mv -i
原生 Python 中的行为,它会是这样的:
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)
除了您还需要代码来处理 wheredstpath
是目录的情况,因此您还需要在fstat
其中添加一个,并且……实际上,您希望阅读C 中的开源实现的源代码mv
,而不是猜测。
更重要的是,你为什么首先要做一个mv -i
?如果您查看您的程序实际在做什么,以及用户体验应该是什么,那么这很可能不是正确的答案。
例如,如果您要求用户提供文件名以将数据保存到其中,您可以将数据写入临时文件,然后mv -i
将其写入用户的文件名……但用户可能更愿意立即验证覆盖,而不是等到您已经生成了临时文件(特别是如果这需要很长时间)。