bashスクリプトの異なるディレクトリにある2つの基本ファイル名の比較

bashスクリプトの異なるディレクトリにある2つの基本ファイル名の比較

2つのファイルディレクトリをパラメータとして使用するbashスクリプトを作成しようとしています。次に、最初のディレクトリのすべてのファイルを繰り返して、2番目のディレクトリにそのファイルがあることを確認します。同じデフォルト名を持つファイルが存在しない場合、ファイルは削除されます。今これが私が持っているものですが、どんな理由であるかすべて一致すると思うので何もしなくなります。

echo "$directory1"
echo "$directory2"
for f1 in "$directory1/*"
do
    echo $f1
    match=no
    for f2 in "$directory2/*"
    do
        echo $f2
        name1="$(basename "$f1")"
        name2="$(basename "$f2")"
        if [ "$name1" == "$name2" ]
        then
            match=yes
            break
        fi
    done
    echo "$match"
    if [[ "$match" == no ]]
    then
        rm "$f2"
    fi
done

答え1

以下は、findを使用して各ディレクトリとベース名のファイルを一覧表示し、並べ替えて並べ替える方法です。次に、各リストをcommに入力し、2番目のディレクトリではなく最初のディレクトリにあるファイルのみを印刷します。リストが期待どおりに表示されたら、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が指摘したように、2番目のディレクトリにはない最初のディレクトリのファイルを削除しようとしているので、適切に変更しました。また、デフォルト名に-aパラメーターを使用しません。

答え2

元のソリューションを修正するには:

  1. @Kusalanandaが言ったように、"$directory1/*"このandを別々"$directory2/*"にsumに置き換える必要があります。それ以外の場合、forループは文字通り「」というファイルを見つけようとします。"$directory1"/*"$directory2"/**
  2. あなたの目標を正しく理解したら、その行は続くrm "$f2"必要がありますrm "$f1"。それ以外の場合、プログラムは一致$directory2しない最後のファイルを$f1削除します。$f1$directory2

これら2つの修正のみを適用すると、スクリプトが機能します(directory1およびにdirectory2正しい値が割り当てられていると仮定)。

しかし、@Kusalanandaが言ったように、別のループを実行する必要はありません。 @Kusalanandaが次のようなことを提案したと思います(echosを削除し、すでに述べたエラーを修正してください)。

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ループですが(なぜならforループが後ろで行われていると信じているからですls)、はるかにきれいに見えます。追加の見積もりがありましたら申し訳ありません。私はそれらを使用する方法を最もよく知りません。

答え3

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

GNUユーティリティを使用すると、同等のbash操作が次のように表示されることがあります。

#! /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

関連情報