“带文件名的文件 B”减去/不带“带文件名的文件 A”又名“A 中删除了什么”?

“带文件名的文件 B”减去/不带“带文件名的文件 A”又名“A 中删除了什么”?

我想将一个大文件夹 A 复制或备份到 B 而无需rsync(只是因为我可以):https://stackoverflow.com/a/65485164/1707015

它有效,但有时我想清理 B 并删除 B 中的旧文件(当它们在 A 中删除时)。

我必须获取 A 中已删除的文件(这样我也可以在 B 中删除它们):

$ cat A_files.txt  # for example: think the small letters as paths like ./some/path/file.yaml
a
c
d
e
f

$ cat B_files.txt
a
b
c
d

$ \grep -f A_files.txt -F -v B_files.txt
b

(反斜杠\只是为了不使用带有颜色或其他内容的任何 grep 别名。)

这有效,但仅适用于小文件。对于每个文件名超过 100 MB 的文件,我需要 > 100 GB RAM :O

有人可以为我提供更节省资源的变体吗?当然可以rsync,但这并不是为了娱乐和练习目的而使用的。

答案1

对于列表连词/减法,标准命令是comm。它适用于已排序的文件行。

B_files.txt因此,对于不在其中的行A_files.txt

export LC_ALL=C # for a simple and deterministic order and allow any byte
                # in file names.
comm -23 <(sort A_files.txt) <(sort B_files.txt)

如果文件已经排序:

comm -23 A_files.txt B_files.txt

这种方法(或您的方法)不适用于任意文件名,因为文件名可以包含换行符,因此不能用线

如果您使用的是 GNU 系统,则可以使用 NUL 分隔记录而不是行,并使用和-z选项。sortcomm

另一种方法是使用 zsh 的数组合/减运算符:

cd /path/to/A || exit
A_regular_files=(**/*(ND.))
cd /path/to/B || exit
B_regular_files=(**/*(ND.))

files_in_B_but_not_in_A=(${B_regular_files:|A_regular_files})

另请注意,除非传递该-x选项,grep否则子字符串是否匹配。例如grep -F foo/bar匹配。blah/foo/barrage

答案2

我想出了:

MY_SOURCE=A_files.txt
readarray -t MY_TARGET_ARRAY < B_files.txt
for LINE in "${MY_TARGET_ARRAY[@]}"; do
    if ! grep -q "${LINE}" "${MY_SOURCE}"; then
        echo "${LINE}";
    fi;
done

尚未测试。可能存在缺失-x和/或缺失的-F问题grep

相关内容