我想将一个大文件夹 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
选项。sort
comm
另一种方法是使用 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
。