Python中的"mv -i"

Nic*_*ick 0 python bash mv

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

aba*_*ert 5

通常,您不希望" mv -i在Python中使用"; 你想在本机中使用命令osshutil在本地执行操作.

但是,如果你希望使用mv -i,你做的方式是什么都一样:

subprocess.check_call(['mv', '-i', srcpath, dstpath])
Run Code Online (Sandbox Code Playgroud)

请记住,重点-i是它是互动的.引自BSD手册页:

导致mv在移动将覆盖现有文件的文件之前写入标准错误的提示.如果标准输入的响应以字符y' or Y' 开头,则尝试移动.

所以,你可能想让它的stdin和stdout通过,所以用户可以直接与它交互.除非您想要弹出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)
Run Code Online (Sandbox Code Playgroud)

但是,这并不完全相同.最严重的是,它具有真实命令所没有的竞争条件(如果您dstnameisfile呼叫和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)
Run Code Online (Sandbox Code Playgroud)

除了你还需要代码来处理dstpath一个目录的情况,所以你也想要fstat在那里添加一个,并且......真的,你想要读源到C语言的开源实现mv,而不是猜测.


更重要的是,你为什么要首先做一个mv -i?如果你看一下你的程序实际在做什么,以及用户体验应该是什么,那么这很可能不是正确的答案.

例如,如果您要求用户输入文件名以保存数据,您可以将数据写入临时文件,然后将mv -i其写入用户的文件名...但是用户可能更愿意立即验证覆盖,而不是等到你已经生成了tempfile(特别是如果需要很长时间).