0

我目前正在将 bash 脚本转换为 python,并且 bash 中有一个命令:mv -i 我知道mv意味着 MOVE,但我不确定如何mv -i在 Python 中使用。我也试过man move,但不能很好地理解它。

4

1 回答 1

5

通常,您不想“mv -i在 Python 中使用”;您想在其中使用命令osshutil以本机方式执行操作。

但是,如果您确实想使用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之间移动不同的文件,它将被覆盖)。但是也有各种细微的差别,比如它不能处理移动多个源文件的情况。isfilemove


如果你想准确地重现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将其写入用户的文件名……但用户可能更愿意立即验证覆盖,而不是等到您已经生成了临时文件(特别是如果这需要很长时间)。

于 2013-06-05T19:31:31.717 回答