从两个文件夹的差异创建存档

Create archive from difference of two folders

我有以下问题。 有两个嵌套的文件夹 A 和 B。它们大部分相同,但 B 有一些 A 没有的文件。 (这是两个已安装的 rootfs 映像)。 我想创建一个执行以下操作的 shell 脚本:

  1. 找出哪些文件包含在 B 中,但不包含在 A 中。
  2. 从 B 复制在 1. 中找到的文件并创建一个包含这些文件的 tar.gz,保持文件夹结构。

目标是之后在包含图像 A 内容的嵌入式系统上导入图像 B 的附加数据。

第一步,我整理了以下代码片段。注意 grep "Nur" : "Nur in" = "Only in" (德语):

diff -rq <A> <B>/ 2>/dev/null | grep Nur | awk '{print substr(, 1, length()-1) "/" substr(, 1, length()-1)}' 

结果是相对于文件夹 B 的路径的输出。

我不知道如何实施第二步。有人可以帮我吗?

使用 diff 查找不存在的文件是严重的矫枉过正;您正在进行大量计算来比较文件的内容,显然您关心的只是文件名是否存在。

也许试试这个。

tar zcf newfiles.tar.gz $(comm -13 <(cd A && find . -type f | sort) <(cd B && find . -type f | sort) | sed 's/^\./B/')

find 命令生成文件名层次结构列表; comm -13 提取第二个输入文件(这里根本不是真正的文件;我们正在使用 shell 的进程替换工具来提供输入)和 sed 命令将路径添加到 B 回到开头。

将命令替换 $(...) 作为参数传递给 tar 是有问题的;如果有很多文件名,你会 运行 变成“命令行太长”,如果你的文件名中包含空格或其他不规则的地方, shell 会把它们弄乱。标准解决方案是使用 xargs,但如果 xargs 最终多次调用 tar,则使用 xargs tar cf 将覆盖输出文件;尽管您的 tar 可以选择从标准输入读取文件名。

find:

$ mkdir -p A B
$ touch A/a A/b
$ touch B/a B/b B/c B/d
$ cd B
$ find . -type f -exec sh -c '[ ! -f ../A/"" ]' _ {} \; -print
./c
./d

想法是使用 exec 操作和 shell 脚本来测试当前文件是否存在于其他目录中。有一些微妙之处:

  • sh -c 的第一个参数是要执行的脚本,第二个(这里是 _ 但也可以是其他任何东西)对应于脚本的 [=17=] 位置参数和第三个 ({}) 是由 find 设置的当前文件名,并作为位置参数 </code>.</li> 传递给脚本 <li>末尾的 <code>-print 操作是必需的,即使它通常是 find 的默认值,因为使用 -exec 会取消此默认值。

使用 GNU 生成 tarball 的示例 tar:

$ cd B
$ find . -type f -exec sh -c '[ ! -f ../A/"" ]' _ {} \; -print > ../list.txt
$ tar -c -v -f ../diff.tar --files-from=../list.txt
./c
./d

注意:如果您有不寻常的文件名,--verbatim-files-from GNU tar 选项可以提供帮助。或者 find-print0 操作和 GNU tar--null 选项的组合 tar.

注意:如果shell是POSIX(例如bash)你也可以从父目录运行find获取路径相对于那里的文件,如果你愿意的话:

$ mkdir -p A B
$ touch A/a A/b
$ touch B/a B/b B/c B/d
$ find B -type f -exec sh -c '[ ! -f A"${1#B}" ]' _ {} \; -print
B/c
B/d