web-dev-qa-db-ja.com

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

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

例:

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によって提供されるいくつかのファイルを除外するオプションを持つ削除コマンドを作成します。

15
stefan83

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
8
L. D. James

この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()関数のコメントを外すことです。

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

10

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

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を実行する前に確認を求めます。
3
gardenhead

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

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

 % 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)。これで、一致するものが見つからない場合に0を返す${keepfiles[(I)filename]}を使用して、キー(ファイル名)が配列に存在するかどうかを確認できます。

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

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

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

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

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

または、あなたの場合

 % rm -- *(+nokeep)

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

1
steeldriver

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

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

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

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
αғsнιη

Bashシェルのextglobshoptがonに設定されていると仮定すると、もう少し保守的な代替策があります。

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

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

0
conny