从两个文件夹的差异创建存档
Create archive from difference of two folders
我有以下问题。
有两个嵌套的文件夹 A 和 B。它们大部分相同,但 B 有一些 A 没有的文件。 (这是两个已安装的 rootfs 映像)。
我想创建一个执行以下操作的 shell 脚本:
- 找出哪些文件包含在 B 中,但不包含在 A 中。
- 从 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
我有以下问题。 有两个嵌套的文件夹 A 和 B。它们大部分相同,但 B 有一些 A 没有的文件。 (这是两个已安装的 rootfs 映像)。 我想创建一个执行以下操作的 shell 脚本:
- 找出哪些文件包含在 B 中,但不包含在 A 中。
- 从 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