Сравнение двух базовых имен файлов в разных каталогах в сценарии bash

Это одна из ловушек использования непрерывного выпуска на основе Sid. Пакеты Haskell проходят пересборку , и в результате дерево пакетов в Sid довольно сломано.

Придется либо ждать разрешения ситуации в Sid, либо использовать версии Buster , в которых доступны все их зависимости. Последний вариант объясняется в руководстве Siduction .

0
03.12.2019, 21:52
3 ответа

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

.
1
28.01.2020, 02:38

Было бы проще с 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
0
28.01.2020, 02:38

Чтобы исправить исходное решение:

  1. Как сказал @Kusalananda, вы должны превратить "$directory1/*"и "$directory2/*"в "$directory1"/*и "$directory2"/*соответственно, иначе цикл for попытается найти файлы с буквальным именем "*".
  2. Если я правильно понимаю вашу цель, строка 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 за кулисами ),но выглядит намного чище. Извините, если есть лишние цитаты. Я не лучший в том, чтобы знать, как их следует использовать.

0
28.01.2020, 02:38

Теги

Похожие вопросы