Для списочных конъюнкций/вычитаний стандартной командой является 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
.
Я придумал:
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
.