ファイルを削除するが、リスト内のすべてのファイルを除外する


16

フォルダーを定期的にクリーンアップする必要があります。テキストを含むファイルリストを取得し、どのファイルが許可されています。次に、このファイルにないすべてのファイルを削除する必要があります。

例:

dont-delete.txt

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

私のフォルダはクリーンアップを行います例としてこれが含まれています:

ls /home/me/myfolder2tocleanup/

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

したがって、このファイルは削除する必要があります。

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

何かを検索して、fileによって提供されるいくつかのファイルを除外するオプションを持つ削除コマンドを作成します。


これは宿題ですか?
mook765

あなたが彼の先生ではないことを願っています。lol
グジャラートサンタナ

2
@gujarat私たちは無料の宿題サービスではないので、コメントは正当化されます。質問自体に関しては、他の人に役立つかもしれないので、これまでのところ公開されています。
セルギーKolodyazhnyy

@Serg私はあなたに完全に同意します
グジャラートサンタナ

回答:


8

rmあなたがチェックし、必要に応じて、それが働いていることを確認できるように、コマンドがコメントアウトされています。次に、その行のコメントを外します。

このcheck directoryセクションでは、誤ったディレクトリから誤ってスクリプトを実行して、間違ったファイルを上書きしないようにします。

echo deleting行を削除してサイレントモードで実行できます。

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done

あなたが知りたいのが一致したかどうかだけである場合の出力の無駄な使用lsと無駄なキャプチャを避けるために、私はあなたのコードを編集しましたgrep。また、固定文字列パターンを使用して、エスケープの問題を回避しました。
デビッドフォースター

@DavidFoerster貢献してくれてありがとう。ただし、whileループをループに変更したときに、for誤ってiteration keyfrom iをに変更しましたf。宣言で、コードを壊しました。それを私が直した。
LDジェームズ

おっと、習慣の力。私はファイル名のシェル変数名をとして短縮する傾向がありますf。;-P(…そして以前に忘れていたあなたの答えに+1。)
デビッドフォースター

10

このpythonスクリプトはこれを行うことができます:

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

重要な部分は、os.unlink()関数のコメントを外すことです。

:このスクリプトをdont-delete.txtに追加しdont-delete.txtて、両方がリストに含まれるようにし、同じディレクトリに保存します。


1
set2番目の部分でO(n)ルックアップの代わりにO(1)のリストの代わりに使用するようにコードを変更しました。
デビッドフォースター

あなたの助けのおかげで、私は通常Windowsの男ですが、Pythonの縫い目もクールです=)
stefan83

1
@ stefan83:PythonはWindows上でも同じように動作します。
デビッドフォースター

3

ワンライナーは次のとおりです。

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls 現在のディレクトリ内のすべてのファイルを(ソート順に)印刷します
  2. sort dont_delete 削除したくないすべてのファイルをソート順に印刷します
  3. <()オペレータは、ファイルのようなオブジェクトに文字列を回します
  4. このcommコマンドは、事前にソートされた2つのファイルを比較し、それらが異なる行を出力します
  5. -2 -3フラグを使用するcommと、最初のファイルに含まれる行のみが印刷され、2番目のファイルは削除されません。これは、削除しても安全なファイルのリストです。
  6. tail +2コールは、ただの見出し削除することですcomm入力ファイルの名前が含まれている出力を、
  7. 次に、標準出力で削除するファイルのリストを取得します。この出力をパイプしてxargs、出力ストリームをの引数のリストに変換しますrm。この-pオプションは、xargs実行前に確認を要求します。

あなたの助けのためのTHX、今私は私の解決策を持っています!
stefan83

@gardenhead、コードは疲れましたが、ディレクトリ内のすべてのファイルが削除され、dont-deleteリストの最初と最後のファイルのみが保持されます。この問題のアイデアはありますか?前もって感謝します。
ネガー

1

FWIWではzsh、これを(+cmd)glob修飾子を使用してネイティブに実行できるようです。

説明のために、いくつかのファイルから始めましょう

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

ホワイトリストファイル

 % cat keepfiles.txt
foo
kazoo
bar

まず、ホワイトリストを配列に読み込みます。

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

またはおそらくより良い

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(bashのmapfileビルトインに相当-またはその同義語readarray)。これで、${keepfiles[(I)filename]}一致が見つからなかった場合に0を返すキーを使用して、配列にキー(ファイル名)が存在するかどうかを確認できます。

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

これを使用して、配列にtrue一致するものがない場合に返す関数を作成できます$REPLY

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

最後に、この関数をコマンドの修飾子として使用します。

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

または、あなたの場合

 % rm -- *(+nokeep)

(ホワイトリストファイル自体の名前をホワイトリストに追加することをお勧めします。)


0

bashシェルがextglob shoptonに設定されていると仮定すると、もう少し保守的な選択肢があります。

rm !($(tr \\n \| < keep.txt))

(...付随する@gardenheadの優れたコミュニケーションの提案!)


0

というファイルにリストされているファイルに空白(スペース/タブ)がないと仮定するとlist、次のようになります。

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \)

-delete上記のコマンドに追加して、リストファイルに存在しないファイルを削除します。検索に-deleteオプションがない場合rm-exec、次のように使用できます。

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} \;

または代わりにターミネーターを使用-exec+ます

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} +

echo ドライランに使用されます。


0

の出力がシェル引数ls /home/me/myfolder2tocleanup/最大制限を超えない限り ARG_MAX Ubuntuの約2MBであるを次のことをお勧めします。


ジョブを実行する1行のコマンド実装は、次のとおりです。

  1. 次のdont-delete.txtように、削除するファイルを含むディレクトリにファイルをコピーします。
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd 次のように削除するファイルを含むディレクトリに移動します。
cd /home/me/myfolder2tocleanup/
  1. ドライランを実行してコマンドをテストし、次のように、実際にファイルを削除せずに、削除対象として検出したファイルの名前を出力するようにします。
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. 出力に満足したら、次のようにコマンドを実行してファイルを削除します。
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

説明:

  • ls -p現在のディレクトリとオプションのすべてのファイルとディレクトリをリストします-p/ディレクトリ名にa を追加します。
  • grep -v / を含むすべてのアイテムを削除してディレクトリを除外します /名前にします。
  • sed 's/\<dont-delete.txt\>//g'除外します dont-delete.txtファイルされるため、プロセスで削除されません。
  • sort 念のため、残りの出力を並べ替えます ls
  • comm -3 - <(sort dont-delete.txt)dont-delete.txtファイルをソートし、ソートされた出力と比較lsし、両方に存在するファイル名を除外します。
  • xargs rmは、の処理済みの出力に残っているすべてのファイル名を削除しますls。これは、ディレクトリファイルにリストされているdont-delete.txtファイル、およびファイル自体を除く、現在のディレクトリ内のすべてのアイテムが削除されることを意味dont-delete.txtます

ドライラン部分:

  • xargs echo 削除する必要があるファイルを印刷します。
  • tr " " "\n" 読みやすくするためにスペースを新しい行に変換します。

-1

私の提案は次のとおりです。

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

更新2018-08-07

例:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

3行目以降にdont-delete.txt内容のあるファイルがあることに注意してください。

./a
./b
./dont-delete.txt

(先頭./非常に重要です

ファイルcd削除されます。


改行で区切られたファイル名のテキストファイルでこれを試しました。その結果、ディレクトリ内のすべてのファイルが削除されました。
ジャックマラプラド

あなたの「キープリスト」が間違っていたと思います。
nyxz

使用例を追加しました。
-nyxz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.