Это одна из ловушек использования непрерывного выпуска на основе Sid. Пакеты Haskell проходят пересборку , и в результате дерево пакетов в Sid довольно сломано.
Придется либо ждать разрешения ситуации в Sid, либо использовать версии Buster , в которых доступны все их зависимости. Последний вариант объясняется в руководстве Siduction .
Вот один из способов сделать это:используйте find, чтобы перечислить файлы в каждом каталоге, используйте базовое имя и sort, чтобы упорядочить их. Затем передайте каждый список в comm и распечатайте только файлы, находящиеся в первом каталоге, но не во втором. Как только список будет выглядеть так, как вы ожидаете, вы можете передать его в rm.
comm -2 -3 <(find "$directory1" -maxdepth 1 -type f | xargs -n1 -d\\n basename | sort) <(find "$directory2" -maxdepth 1 -type f | xargs -n1 -d\\n basename | sort) | xargs -d\\n printf "$directory1/%s\n" | xargs -d\\n rm
примечание :, как указал @LeviUzodike, вы хотели удалить файлы в первом каталоге, не найденные во втором, поэтому я внес соответствующие изменения. Я также избегал использования аргумента -для базового имени
.Было бы проще с zsh
и его ${array1:|array2}
оператором вычитания массива:
#! /bin/zsh -
dir1=${1:?} dir2=${2:?}
dir1_files=(${dir1%/}/*(DN:t))
dir2_files=(${dir2%/}/*(DN:t))
only_in_dir2=(${dir2:|dir1})
(($#only_in_dir2 == 0)) ||
rm -rf -- $dir2/$^only_in_dir2
Для bash
и утилит GNU эквивалентом может быть что-то вроде:
#! /bin/bash -
dir1=${1:?} dir2=${2:?}
export LC_ALL=C
chdir() {
case $1 in
(/*) CDPATH= cd -P "$1";;
("") echo >&2 invalid empty directory; false;;
(*) CDPATH= cd -P "./$1";;
esac
}
list_files() (
shopt -s nullglob dotglob # equivalent of zsh's ND
chdir "$1" &&
set -- * &&
(($# > 0)) &&
printf '%s\0' "$@"
)
comm -z13 <(list_files "$dir1") <(list_files "$dir2") |
(chdir "$dir2" && xargs -r0 rm -rf --)
Да, хотите верьте, хотите нет, эта функция chdir
— это то, как вы переходите в произвольный каталог в оболочках POSIX и то, что POSIX будет рекомендовать в следующей редакции стандарта .
Обратите внимание, что в случае zsh
, если dir1
не читается, все файлы в dir2
будут удалены.
С bash
будет случай, если dir1
не читается или не доступен для поиска (, поскольку cd
требуется поиск разрешение ).
Если вы хотите выйти из -в случае ошибки при попытке создать список соответствующих файлов, вы можете сделать что-то вроде:
#! /bin/zsh -
dir1=${1:?} dir2=${2:?}
zmodload zsh/system || exit
ERRNO=0
dir1_files=(${dir1%/}/*(DN:t))
dir2_files=(${dir2%/}/*(DN:t))
if ((ERRNO)); then
syserror -p "An error occurred when trying to read the directories: "
exit 1
fi
only_in_dir2=(${dir2:|dir1})
(($#only_in_dir2 == 0)) ||
rm -rf -- $dir2/$^only_in_dir2
Чтобы исправить исходное решение:
"$directory1/*"
и "$directory2/*"
в "$directory1"/*
и "$directory2"/*
соответственно, иначе цикл for попытается найти файлы с буквальным именем "*
". rm "$f2"
должна быть rm "$f1"
, иначе программа просто удалит последний файл в $directory2
, который не соответствует $f1
, когда $f1
— это файл, который должен быть удален, потому что он просто не соответствует всем файлам в $directory2
. Только с этими двумя исправлениями ваш скрипт должен работать (при условии, что directory1
и directory2
назначены правильные значения.)
Но, как сказал @Kusalananda, вам не нужно делать еще один цикл. Я думаю, что @Kusalananda предлагал вам сделать что-то вроде этого (убрать echo
и исправить уже упомянутые ошибки):
for f1 in "$directory1"/*
do
# ls "$directory2"/$(basename "$f1") &>/dev/null
# if [[ $? != 0 ]]
# EDIT below from @Kusalananda
if [[ -e "$directory2/$(basename "$f1")" ]]
then
rm "$f1"
fi
done
Технически это еще один цикл for (, потому что я считаю, что ls
выполняет цикл for за кулисами ),но выглядит намного чище. Извините, если есть лишние цитаты. Я не лучший в том, чтобы знать, как их следует использовать.