高级文件过滤

高级文件过滤

我有 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 仅匹配整个整行

相关内容