
ВОтветна другой вопрос, я хотел использовать структуру, похожую на эту, чтобы найти файлы, которые появляются в , 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
не может обрабатывать записи, завершающиеся нулем. (Немного предыстории: я передаю в вычисляемый список 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, но вы можете использовать