详细解析了在使用 Rclone、rsync 和 Docker COPY/ADD命令时,路径末尾是否添加斜杠(`/`)对文件复制和同步行为的影响。通过多个示例,文章展示了不同工具在处理文件夹到文件夹、文件到文件夹、文件到文件等场景时的差异。总结要点包括:Rclone 对斜杠不敏感,rsync 斜杠影响源路径行为,而 Docker COPY/ADD 斜杠决定目标路径是文件还是文件夹。
日常中可能经常会使用到与同步或文件复制有关的命令,针对不同的场合分为很多种情况,比如复制文件到文件夹、复制文件夹到文件夹、复制文件夹里的内容到文件夹等。如果是文件夹的话可能需要考虑需不需要加斜杠,例如名为 dest 的文件夹是写成dest/还是dest好。而实际上不同的工具或软件对于加不加斜杠的处理大有不同。
以如下的场景为例:
|
|
注意下文的每一次运行命令,默认都是在如上的文件结构上运行的。
对于如同command /path/a /path/b的命令来说,我们把/path/a称作前一个路径,/path/b称为后一个路径。
Rclone 的场合
Rclone 应该来说各种场合是一致性最强的了。一句话总结就是:斜杠无关紧要。第一个路径可以是文件或文件夹,后一个路径只能是文件夹。
文件夹->文件夹
前后两个目录都是文件夹时,不管有没有斜杠,Rclone 的语义始终是「把前面那个文件夹底下的所有文件都复制到后一个文件夹底下」。
运行命令:
|
|
结果:
|
|
可以看到把 src_folder 里的文件都复制到 dest_folder 下面了,而非形成类似 dest_folder/src_folder 的结构。
文件->文件夹
运行命令:
|
|
结果:
|
|
可以看到并不会把 src_content1.txt 复制到 dest_folder 底下改名成 a.txt,而是把后一个路径始终看成是文件夹,因为不存在而新建了一个名为 a.txt 的文件夹。
文件->文件
想使用 Rclone 把一个文件复制到另一个文件夹底下并改名,这点是做不到的。原因上面已经说了,Rclone 后一个路径只能是文件夹。
rsync 的场合
rsync 的斜杠之和前一个路径参数(原)有关,后一个路径参数(目的地)加不加斜杆都无所谓。
文件夹->文件夹
前一个路径不加斜杠
运行命令:
|
|
结果:
|
|
可以看到前一个路径没加斜杠,就把整个 src_folder 连文件夹带文件都拷贝到 dest_folder 底下了。
运行命令:
|
|
结果:
|
|
还是连文件夹带文件拷贝,不过会自动新建后一个路径不存在的 new_folder 文件夹。
前一个路径加斜杠
运行命令:
|
|
结果:
|
|
前一个路径是文件夹且后面加斜杠,意思就是把该文件夹下的所有文件拷贝到后一个目录下,不带文件夹本身。
运行命令:
|
|
结果:
|
|
这次是拷贝 src_folder 下的所有文件,后一个路径中的 new_folder 由于不存在所以会自动新建。
文件->文件夹 / 文件->文件
如果前一个路径是文件的话,这时候对于后一个路径来说要分几种情况。
为了方便说明我们把诸如 aa/bb/cc 的目录看作以/隔开的 seg,其中 aa 是一个 seg、bb 是一个 seg、cc 是一个 seg。因此对于这个路径来说,cc 就是它的最后一个 seg。下面分几种情况:
-
后一个路径的最后一个 seg 不存在:把最后一个 seg 作为文件名,用前一个路径的文件内容写进来
-
后一个路径的最后一个 seg 存在:
- 后一个路径是文件夹:把前一个路径的文件拷贝到后一个路径的文件夹下
- 后一个路径是文件:用前一个路径的文件覆盖后一个路径的文件
-
后一个路径的超过一个 seg 不存在:复制失败(并不会进行
mkdir -p类似的操作)
后一个路径的最后一个 seg 不存在
运行命令:
|
|
结果:
|
|
src _content1.txt 的内容被写到了 aaa.txt 中。
后一个路径的最后一个 seg 存在
后一个路径是文件夹
运行命令:
|
|
结果:
|
|
src_content.txt 文件被复制到了 dest_folder 中。
后一个路径是文件
运行命令:
|
|
结果:
|
|
可以看到 dest_content.txt 的文件内容被 src_content1.txt 的内容覆盖。
后一个路径的超过一个 seg 不存在
如下所示,会报错:
|
|
Docker 的场合
Docker 的情况是,使用 COPY 或 ADD 命令时,前一个路径只看是文件还是文件夹,是否有斜杠无关紧要。后一个路径可以是文件或文件夹,通过是否有斜杠来判断。
如果 Docker 中后一个路径的文件夹不存在,不管有几层都会自动新建。
我们这次用以下的目录结构做测试:
|
|
文件夹->文件夹
运行命令:
|
|
结果:
|
|
不管前面加不加斜杠,都是把 src_folder 目录下的所有内容复制到/test/dest_folder 底下去,不包括 src_folder 本身。那如果一定要保留 src_folder 怎么办?只能自己在后面加一个文件夹名了,比如:
|
|
文件->文件夹 / 文件->文件
如果前一个目录是文件,需要分两种情况来讨论。
后一个路径加斜杠(文件->文件夹)
运行命令:
|
|
结果:
|
|
可以看到如果后一个路径加了斜杆的话,会把它当做文件夹看待,而把前一个路径的文件复制到指定的文件夹下。
后一个路径不加斜杠(文件->文件)
运行命令:
|
|
结果:
|
|
这里出现了非预期行为。实际上由于后一个路径没有加斜杠,Docker 把后一个路径当做了文件,而把 src_content1.txt 的内容拷贝了过来。这里 tree 命令显示的 dest_folder 其实是一个文件,不是文件夹,其文件内容是 src_content1.txt 的内容。
这种情况其实还能同时复制多个文件,比如官方文档中的例子:
|
|
会把这两个文件复制到 things 文件夹下。同时,前一个路径是通配符也是可以的,比如file*.txt。