我能阻止wget创建重复文件吗?

如果我运行wget两次,它不会识别已经下载了该文件,并会创建一个新的。有没有办法防止它再次下载该文件?

$ wget https://cdn.sstatic.net/askubuntu/img/logo.png
...
Saving to: ‘logo.png’
...

$ wget https://cdn.sstatic.net/askubuntu/img/logo.png
...
Saving to: ‘logo.png.1’
...

(如果wget无法完成此任务,可以使用curl或类似的可脚本化替代工具。)

9它会创建一个新的文件,因为它确实识别到该文件存在! - nico
我遇到了同样的问题。换句话说,你想要“狠狠地”或者替换文件,但是还没有人提出这个解决方案,至少目前为止还没有。我刚刚想到了另一个解决方案,在wget之后使用rm example.1,但是已经接受的解决方案也很好。 - PJ Brunet
4个回答

我建议你使用-N选项。
-N
--timestamping
    Turn on time-stamping.

它可以进行时间戳,只有在服务器上的文件版本较新时才重新下载文件。
$ wget -N https://cdn.sstatic.net/askubuntu/img/logo.png
...
Saving to: ‘logo.png’
...

$ wget -N https://cdn.sstatic.net/askubuntu/img/logo.png
...
Server file no newer than local file ‘logo.png’ -- not retrieving.

注意事项(来自αғsнιη的评论)

如果服务器配置不正确,可能会始终报告文件是新的,并且-N将始终重新下载该文件。在这种情况下,-nc可能是一个更好的选择。


3当服务器配置不正确时,-N 可能会失败,并且 wget 将始终重新下载。因此有时 -nc-N 更好。 - αғsнιη
1@Kasiy,谢谢你的评论,似乎没有一个适用于所有情况的好选择。 - jofel
虽然我喜欢这个解决方案,但如果是同一个文件但日期更新了呢?那样就没有理由重新下载了。话虽如此,这似乎是最好的答案。至少在wget添加一个类似于“只有远程文件发生变化时才替换/覆盖此文件”的功能之前是这样。 - PJ Brunet

是的,这是-c选项。
--continue
    Continue getting a partially-downloaded file.  This is useful when you want to
    finish up a download started by a previous instance of Wget, or by another
    program.

如果文件相同,第二次下载尝试将停止。
$ wget -c https://cdn.sstatic.net/askubuntu/img/logo.png
...
Saving to: ‘logo.png’
...

$ wget -c https://cdn.sstatic.net/askubuntu/img/logo.png
...
The file is already fully retrieved; nothing to do.

注意事项(来自jofel的评论)

如果服务器上的文件发生了变化,-c选项可能会给出错误的结果。

使用-c,wget只是简单地向服务器请求已下载文件之外的任何数据,仅此而已。它不会检查已下载文件部分是否有任何更改。因此,你可能会得到一个混合了旧文件和新文件的损坏文件。


本地测试

您可以通过以下方式运行简单的本地Web服务器进行测试(感谢@roadmr答案):

打开一个终端窗口并输入:

cd /path/to/parent-download-dir/
python -m SimpleHTTPServer

现在打开另一个终端并执行以下操作:
wget -c http://localhost:8000/filename-to-download

请注意,filename-to-download 是位于 /path/to/parent-download-dir/ 目录中的文件,我们希望下载它。
现在,如果您多次运行wget命令,您将会看到:
The file is already fully retrieved; nothing to do.

好的,现在进入`/path/to/parent-download-dir/`目录,并向源文件中添加一些内容。例如,如果它是一个文本文件,在其中添加一行简单的额外内容并保存文件。然后使用`wget -c ...`进行尝试。很好,现在你会看到文件重新下载,但你之前已经下载过它了。
原因:为什么会重新下载?
因为文件的大小变得比之前下载的文件更大,除此之外没有其他原因。

1如果文件在下载之间在服务器上发生了更改,那么这个方法将无法正常工作。在最糟糕的情况下(文件大小增加),你会得到一个损坏的文件。 - jofel
1@jofel 是的,-nc 不像你说的那样有效,但是 -c 选项会起作用,这就是为什么我首先提到了 -c 选项。 - αғsнιη
使用-c选项,wget只会向服务器请求已下载文件之后的数据,不会进行其他检查。它不会检查服务器上已下载文件部分是否发生了任何更改。最糟糕的情况是你得到一个损坏的文件,这个文件是旧文件和新文件的混合体。 - jofel
在审查了选项后,我认为这仅对像日志文件这样的东西有用(保证增量更新),在其他所有情况下,我认为-N或-nc更合适,因为它们处理整个文件。 - lofidevops

还有另一个选项叫做-nc,用于wget命令。
--no-clobber
   If a file is downloaded more than once in the same directory, Wget's behavior
   depends on a few options, including -nc.  In certain cases, the local file will
   be clobbered, or overwritten, upon repeated download.  In other cases it will be
   preserved.

当指定了-nc选项时,Wget将拒绝下载相同文件的副本。如果你已经有了与wget尝试下载的相同文件,除非你重命名或删除本地文件,否则它将拒绝下载。
$ wget -nc https://cdn.sstatic.net/askubuntu/img/logo.png
...
Saving to: ‘logo.png’
...

$ wget -nc https://cdn.sstatic.net/askubuntu/img/logo.png
File ‘logo.png’ already there; not retrieving.

有时候这个选项非常好,我建议使用-nc选项而不是-c或者-N选项,因为如果这些选项与本地文件同名,它们会覆盖下载文件。
注意事项(来自jofel的评论)
如果文件在服务器上发生了变化,-nc选项不会更新文件。如果你知道文件会发生变化,最好使用-N选项。如果你知道文件不会发生变化(或者你不关心),那么-nc就可以了。

我知道这是一个关于wget的具体问题,但OP提到了“如果wget不能做到这一点,可以使用curl或类似的可脚本化替代方法。” 我不确定这里的要求是什么(多个文件,如果与原始文件不同则保留旧版本,用新下载的版本替换)。根据您想要的和您想要如何处理重复文件的方式,您可能需要更多的东西。实现您所需的非常简单的方法就是使用curl。
curl http://cdn.sstatic.net/askubuntu/img/logo.png?v=ca4d192163aa > logo.png

这个命令会每次用新下载的文件替换旧文件。
如果你下载的是二进制文件而不是文本文件,请不要将其输出到终端(不带“> [文件名]”)。这样做可能会干扰你的终端会话。如果你不小心这样做了,可能需要打开另一个Shell/终端会话。

如果您的终端因为显示二进制文件而损坏,可能比打开一个新的终端更容易调用程序“reset”。 - jofel
你说得对,我对我的要求没有表达清楚,好的结果是我学到了更多选择 :) 谢谢 - lofidevops
谢谢 @jofel ^^ 不知道有"重置"这个功能,我一直都是关闭再打开一个新标签页,然后关闭那个乱码的页面...虽然这种情况并不经常发生。 - Goblinlord