2つのディレクトリ内のファイル名の一部を比較する


0

Directory1とDirectory2という2つのディレクトリがあります。両方とも、いくつかの数字と文字列を含む画像を含んでいます。Directory1には、番号と001_blur.pngのような_blur文字列のぼやけた画像が含まれています。約62kの画像が含まれています。Directory2には、001_fine.pngなどの対応する細かい画像が含まれています。60kの画像が含まれています。

問題は、Directory2に対応する素晴らしいペアがあるDirectory1からのぼやけた画像をいくつか失ったことです。そして、Directory1に対応するぼかし画像があるDirectory2のいくつかの素晴らしい画像を失いました。

今、私は対応するペアを持つ画像だけを保存したいと思います。対応する画像の1つが存在しない場合、それらを削除し、画像をペアで配置したいだけです。

私のディレクトリ形式は次のとおりです。

Directory1
    001_blur.png
    002_blur.png
    003_blur.png
    004_blur.png

Directory2
    001_fine.png
    002_fine.png
    003_fine.png
    005_fine.png

注:001ペア、002ペア、および003ペアを保持したいと思います。ぼかしをDirectory3にコピーし、Directory4にコピーします。

画像は各フォルダーで約60kなので、この問題にはアルゴリズムの複雑さもあると思います。Directory1から1つの画像を取得し、Directory2で対応する細かい画像を検索しようとすると、複雑さが高くなると思います。それでは、このアルゴリズムの複雑さをどのように扱うのでしょうか?

回答:


1

ディレクトリコンテンツを1回読み取り、テキストデータを解析し、最後にファイルを削除するalloのアプローチは良いようです。ただし、その答えは、2つのディレクトリのファイル名の違いを認めないようです(blurvs. fine)。

ファイルにはパターンに従って名前が付けられているため、印刷できない文字や改行などの厄介な驚きをファイル名に含めることはできません。解析lsは安全なはずですが、一般的にはそうすべきではありませんlsここでは解析しないように、一般的な解決策を提供したいと思います。私は、nullで終わる文字列、それゆえのようなスイッチを使用します-print0と、-zすべての上に。

始めましょう。別のファイルシステムにコピーしない限り、変数宣言のパスを調整するだけで済みます。その場合は、調整する必要がありますcp -l最初にコメントを読んでください。コードブロック全体をファイルに貼り付け、調整してから、ソースまたは実行することをお勧めします。

#/bin/bash

# Declare variables.
dir1="/your/directory1/"
dir2="/your/directory2/"
dir3="/your/new/directory3/" # Use absolute paths at least for dir3...
dir4="/your/new/directory4/" # and dir4.
core1=blur
core2=fine

# Create temporary file.
tmpf=$(mktemp)

# Get null-terminated local paths from dir1.
# Note the line doesn't end yet thanks to \.
{ (cd "$dir1"; find -maxdepth 1 -type f -iname "*${core1}*" -print0) ; \

# Add null-terminated local paths from dir2
# (the line continues because of the trailing |)
(cd "$dir2"; find -maxdepth 1 -type f -iname "*${core2}*" -print0) |

# but convert core2 to core1, so the names are all with core1.
# Note the output of the two finds is gathered by {} and piped...
sed -z "s|${core2}|${core1}|" ; } |

# ...to sort and uniq. With uinq -d we print only duplicates, only once.
sort -z | uniq -zd > "$tmpf"

# Note how long this one line was.

# At this moment tmpf lists all the files we need to copy to dir3.
# The filenames are local to dir1, so we have to cd temporarily.
# dir3 will be resolved from dir1, that's why I told to use absolute paths.
# I assume the same filesystem. Creating hardlinks instead of copying;
# remove -l option to do regular copy. Hardlinking.
(cd "$dir1"; xargs -0 -a "$tmpf" cp -alt "$dir3")

# Convert core1 to core2 in tmpf in place.
sed -zi "s|${core1}|${core2}|" "$tmpf"

# Hardlinking from dir2 to dir4.
(cd "$dir2"; xargs -0 -a "$tmpf" cp -alt "$dir4")

# Remove the temporary file.
rm "$tmpf"

dir1は "$ dir1"で、dir2でも同じであると思います。しかし、これらの変更を加えて実行すると、cp:missing file operandと表示されます。このような-exec cp {}を使用する必要があると思います。私はわかりません。
ダルマ

@Dharmaありがとう。私にとっては教訓です。テスト環境で同じディレクトリ名とその変数を使用しないでください。そうしないと、そのようなバグがすり抜けてしまいます。cp今のところ問題を特定できません。OSを教えてください。
カミルマシオロウスキ

私はubuntu 14.04 LTSに取り組んでいます。
ダルマ

@Dharma OK、missing file operand$tmpf空の場合、つまりすべてfindが何も見つからなかった場合に返されます。自分でデバッグするときは、必ず引用符で囲まれている$dir1$dir2?または多分core1core2間違って設定されていますか?(たとえば、質問で「ぼかし」と「細かい」を使用しましたが、実際にはファイルは他の言語で記述されています)。
カミルマシオロウスキ

すばらしい。申し訳ありませんが、ミスタック、罰金を科せられました。どうもありがとうございます。
ダルマ

0

次のループを使用して、すべてをDirectory3に入れてから、Directory1とDirectory2を削除できます。

mkdir Directory3
cd Directory1
for file in *
do
    # note that the second "cp" is only executed if the first one succeeds:
    cp ../Directory2/${file/blur/fine} ../Directory3/ 2>/dev/null && cp $file ../Directory3/
done
cd ..
#rm -rf Directory1 Directory2

0

_blur対応する `_fine |のない画像を削除するには:

for f in Dir1/*blur.png;do [[ -f Dir2/$(basename $f _blur.png)_fine.png ]] || echo rm $f;done

上記のように一度試してから、正しいことをしているようであれば、echo実際にファイルを削除するために削除します。

_fine対応するものがないものを削除するコマンド_blurは、読者への課題として残されています。


0

2つのソートされたdirlistingを作成し、それらを比較できます。

# create the listings
cd Directory1;ls|sed 's/_blur\.png//' >../list1.txt;cd ..
cd Directory2;ls|sed 's/_fine\.png//' >../list2.txt;cd ..
# sort the items, then deduplicate them (uniq) and add the count (-c)
cat list1.txt list2.txt|sort|uniq -c >counts.txt

これにより、1または2で始まるファイル名のリストが表示されます。

# for each line which starts with a 1, remove the 1 and use it as filename
for file in $(grep '^1' counts.txt|sed 's/^1 //');do
    # delete it from first or second directory
    test -f "Directory1/${file}_blur.png" && echo rm "Directory1/${file}_blur.png"
    test -f "Directory2/${file}_fine.png" && echo rm "Directory2/${file}_fine.png"
done

動作する場合、エコーを削除します。ただし、前にテストしてください。


どのようにあなたのソリューションは、ファイル名が異なっているという事実(ハンドルんblur対をfine)?見えません。
カミルマシオロウスキ

申し訳ありませんが、私はそれを処理しませんでした。seddirlistingsからサフィックスを削除し、deleteコマンド用に追加することにより、回答を更新しました。しかし、スクリプトは高速で汚れたシェルパイプには複雑すぎて、別の方法で解決することを検討します(つまり、globおよびshutilsモジュールを使用した短いpythonスクリプトを使用)。
アロ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.