假设我有这些文件:
old/common-change/index.html
new/common-change/index.html
new/only-new/index.html
old/only-old/index.html
的输出diff -qr
接近我想要的:
$ diff -qr old/ new/
Files old/common-change/index.html and new/common-change/index.html differ
Only in new/: only-new
Only in old/: only-old
但是,对于那些仅在 中的文件new/
,我想要它们的文件名。不仅仅是父目录。我也尝试过使用diff -qrN
,但是我无法轻松过滤掉仅位于old/
.
$ diff -qrN old/ new/
Files old/common-change/index.html and new/common-change/index.html differ
Files old/only-new/index.html and new/only-new/index.html differ
Files old/only-old/index.html and new/only-old/index.html differ
因为我想找到不同但也包含在new/
.我想删除仅包含在old/
.
我想要获取diff
输出的唯一文件是:
new/common-change/index.html
new/only-new/index.html
如果重要的话,上下文是我想弄清楚自我的网站存储库中上次提交以来哪些页面发生了更改。我正在将以前的版本构建为old/
,将当前版本构建为new/
.因此,我想在所有更改的页面上运行测试,但忽略已删除的页面(因为我无法在不存在的页面上运行测试)。
答案1
使用zsh
,您可以执行以下操作:
zmodload zsh/stat
old=(old/**/*(ND-.)); old=(${old#old/})
new=(new/**/*(ND-.)); new=(${new#new/})
# in new, not in old:
new_files=(${new:|old})
# loop over files common to both sets:
for file (${old:*new}) {
stat -A old_size +size -- old/$file || continue
stat -A new_size +size -- new/$file || continue
# compare size to avoid calling cmp as an optimisation
(( old_size == new_size )) ||
cmp -s -- {old,new}/$file ||
new_files+=($file)
}
将结果放入 中$new_files
,使用类似的方法ls -ld -- new/$^new_files
将该列表传递new/
给每个 to ls
。
答案2
可能不是最好的解决方案,但我用一系列管道想出了一些办法:
diff -qrN old/ new/ |
grep -oP '(?<=\s)new\/\S*' |
xargs -rd '\n' ls -1d 2>/dev/null
我想知道是否有更好的方法来做到这一点。
答案3
一种选择可能是在 dry-run + checksum 模式下使用rsync
,这里将结果存储在 bash 4.4+ 数组中,并使用rsyncperl
来解码\#ooo
序列来编码一些字节值:
readarray -td '' new_files < <(
rsync --out-format=%f -rcn new/ old/ |
perl -p -l0 -e 's/\\#([0-7]{3})/chr(oct($1))/ge'
)
与 中相同zsh
,使用0
参数扩展标志来分割 NUL 分隔列表:
new_files=(
${(0)"$(
rsync --out-format=%f -rcn new/ old/ |
perl -p -l0 -e 's/\\#([0-7]{3})/chr(oct($1))/ge'
)"}
)