
結束於一個答案對於另一個問題,我想使用類似這樣的結構來查找出現在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 中修復,但您可以使用