我有 3 个不同的文件夹:历史记录、收件箱、备份。
我需要将所有文件从“历史记录”复制到“收件箱”,前提是它们不存在于“备份”中。
这个怎么做?
答案1
举个例子,历史中有子文件夹吗?
for x in history/*;
do
[[ -f backup/"$(basename "$x")" ]] || cp "$x" inbox
done
该脚本将循环遍历history文件夹中所有可能的文件,并提取它的基名(例如/bin/ls的基名是ls),并检查该文件是否存在于备份文件夹中;如果没有,请执行复制程序。
答案2
这个简单的脚本仅在三个目录不包含任何子目录时才有效(需要更复杂的递归算法来处理这种情况)。
Warlock 的答案很好,但与 Warlock 的单行脚本相比,这样的脚本的优点是,通过使用 xargs,我们不会为复制的每个文件创建 cp 实例。每次 xargs 生成一个满足 shell 命令行长度限制的命令行时,我们只分叉一个 cp 实例。这在现代系统上往往是巨大的,因此我们很可能只运行 cp Total 的一个实例,即使是历史上数百或可能数千个文件/
#! /bin/sh
# use tempfile(1) if available, otherwise use:
# EXCLUDEFILE="/tmp/excl.$$"
EXCLUDEFILE=$(tempfile -p excl)
# generate an exclude file, changing backup/ to history/
find backup/ -type f | sed -e 's:^backup/:history/:' > "$EXCLUDEFILE"
find history/ -type f -print0 | \
grep -z -Z -F -v -x -f "$EXCLUDEFILE" | \
xargs -0r -i{} cp {} inbox/
rm "$EXCLUDEFILE"
仅供参考,这里使用的 grep 选项的长格式是:
grep --null-data --null --fixed-strings --invert-match \
--line-regexp --file "$EXCLUDEFILE"
更紧凑的形式是:
grep -zZFvxf "$EXCLUDEFILE"
大多数选项都是常用的或不言自明的,但其中三个可能需要一些解释:
-z
或--null-data
告诉 grep 期望以 null 结尾的输入(来自find -print0
)
-Z
或--null
告诉 grep 输出以 null 结尾的行(通过管道传输到xargs -0
)
-x
或--line-regexp
告诉 grep 仅匹配整个整行