结束于一个答案对于另一个问题,我想使用类似这样的结构来查找出现在list2
但未出现在中的文件list1
:
( cd dir1 && find . -type f -print0 ) | sort -z > list1
( cd dir2 && find . -type f -print0 ) | sort -z > list2
comm -13 list1 list2
然而,我遇到了困难,因为我的版本comm
无法处理以 NULL 结尾的记录。 (一些背景:我将计算列表传递给rm
,所以我特别希望能够处理可能包含嵌入换行符的文件名。)
如果你想要一个简单的例子,试试这个
mkdir dir1 dir2
touch dir1/{a,b,c} dir2/{a,c,d}
( cd dir1 && find . -type f ) | sort > list1
( cd dir2 && find . -type f ) | sort > list2
comm -13 list1 list2
如果没有以 NULL 结尾的行,此处的输出是./d
仅出现在 中的单个元素list2
。
我希望能够用来find ... -print0 | sort -z
生成列表。
如何最好地重新实现一个等效项,输出出现在但未出现在 中comm
的以 NULL 结尾的记录?list2
list1
答案1
GNU comm
(从 GNU coreutils 8.25 开始)现在有一个-z
/--zero-terminated
选项。
对于旧版本的 GNU comm
,您应该能够交换 NUL 和 NL:
comm -13 <(cd dir1 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) \
<(cd dir2 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) |
tr '\n\0' '\0\n'
这种方式comm
仍然适用于换行符分隔的记录,但输入中的实际换行符编码为 NUL,因此我们仍然可以安全地处理包含换行符的文件名。
您可能还需要将语言环境设置为,C
因为至少在 GNU 系统和大多数 UTF-8 语言环境中,有不同的字符串排序相同,并且会导致此处出现问题。
这是一个非常常见的技巧(参见反转匹配行,NUL 分隔另一个例子是comm
),但需要在输入中支持 NUL 的实用程序,这在 GNU 系统之外相对较少。
示例:
$ touch dir1/{①,②} dir2/{②,③}
$ comm -12 <(cd dir1 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) \
<(cd dir2 && find . -type f -print0 | tr '\n\0' '\0\n' | sort)
./③
./②
$ (export LC_ALL=C
comm -12 <(cd dir1 && find . -type f -print0 | tr '\n\0' '\0\n' | sort) \
<(cd dir2 && find . -type f -print0 | tr '\n\0' '\0\n' | sort))
./②
(2019年编辑:①②③的相对顺序已在较新版本的 GNU libc 中修复,但您可以使用