1行に以下を行うことは可能ですか?
shopt -s extglob
rm -r !(folder1|file1|folder2)
rm -r folder2/!(subfolder)
rm -r folder2/subfolder/!(onefile)
例えばこんなこと?
rm -r !(folder1|file1|folder2/subfolder/onefile)
答え1
-path
ツールの(マイナス)テストを使用できますfind
。ツールがサポートしている場合は-delete
比較的簡単です。
find . ! -path ./folder1 ! -path './folder1/*' ! -path ./file1 ! -path ./folder2/subfolder/onefile -delete
onefile
存在する場合はエラーが報告さsubfolder
れます。これにより生き残ることができますが、終了状態は維持されません。folder2
cannot delete: Directory not empty
find
0
find
サポートしている場合は、-empty
ディレクトリの前にディレクトリが空であることをテストできます-delete
。一般的に言えば、ディレクトリ以外の項目が空であることをテストしたくありません。これによりコマンドが複雑になりますが、0
すべてが計画通りに進むとコマンドが返される可能性があります。このように:
find . ! -path ./folder1 \
! -path './folder1/*' \
! -path ./file1 \
! -path ./folder2/subfolder/onefile \
\( ! -type d -o -empty \) \
-delete
find
支援できる資金が十分で、-delete
おそらく-empty
そうです-regex
。私のDebianのGNUはfind
次のことができます:
find . ! -regex '\./folder1/*.*\|\./file1\|\./folder2/subfolder/onefile' -delete
メモ:
onefile
find
これは削除subfolder
または存在を防ぎますfolder2
。これらのディレクトリが存在するかどうかに関係なく、これらのディレクトリを保存するには、より多くのパターン(以下を参照)またはより複雑な正規表現が必要ですonefile
。より複雑な正規表現を使用した変形:find . ! -regex '\./folder1/*.*\|\./file1\|\./folder2\(/subfolder\(/onefile\)?\)?' -delete
ボーナスとして、この改善は「ゼロ以外の終了状態」の問題を解決します。
-path
globなどのパターンマッチング表記を使用します(?
単一文字に一致し、*
ゼロ文字以上に一致)。-regex
正規表現を使用します(.
単一文字に一致し、.*
ゼロ文字以上に一致)。-path
-regex
ファイルのフルパスと一致します。効果的なパターンを設計するには、find
どのパスが使用されるかを知る必要があります。ヒント:find
始点以外のパスには、末尾のスラッシュを使用しない義務があります。だから()とファイル-path
に./folder1
別々のモードを使用します./folder1/*
。- 一方、始点は指定されたとおりに使用されます。始点がある場合、すべてのパスは自分のパスを除いて
.
開始されます。すると になります。始点がある場合、すべてのパスが始まります。./
.
.
./
./
私のテストでは
-delete
自動的に処理され.
削除されず、エラーが発生しないため、除外する必要はありません.
。一方、エラーが発生します./
。この動作がどのくらい信頼できるかわかりません。疑わしい場合は、明示的に除外してください.
。特に意味のある終了状態を探している場合にはさらにそうです。正規表現型はほとんどありません。。たとえば、
-regextype posix-extended
beforeを使用できます! -regex
。私が思いついた最も簡単なコマンド(携帯用ではありませんが):find . -regextype posix-extended \ ! -regex './folder1(/.*)?|./file1|./folder2(/subfolder(/onefile)?)?' \ -delete
.
意図的に(リテラルドット)の代わりに(ワイルドカード)を\.
先頭点として使用しました.
。開始点があるため、.
すべてのパスは.
確実に始まるため、ワイルドカードは以外のものと一致しません.
。\.
正式な精度を好む場合は使用してください。あまり削除しない場合は、コマンドを「テスト実行」できます。
-delete
に変更する-print
と、削除したい項目が表示されます。これは次のように修正された最初のコマンドです。find . ! -path ./folder1 ! -path './folder1/*' ! -path ./file1 ! -path ./folder2/subfolder/onefile -print
または、以前のテストをすべて無効にする全体的に(これは、何を変更すべきかを知らない限り、個別に否定するものとは異なります。比較してください。これ到着これ)変更して何が生き残るかを確認
-delete
します-print
。find . ! \( ! -path ./folder1 ! -path './folder1/*' ! -path ./file1 ! -path ./folder2/subfolder/onefile \) -print
引用符を使用しないと
./folder1/*
エラーが発生します。シェルは拡張を試みます*
。
-path
はいPOSIXの要件しかし、-delete
そして-regex
いいえ-empty
。時には-exec rm {} +
代わりに使用することもできますが、必要なディレクトリは削除されません-delete
。はい、ディレクトリを削除することもできますが、全体のポイントも削除され無効になります。rm
rmdir
rm -r
rm -r ./folder2
./folder2/subfolder/onefile
-delete
私たちの基本的なアプローチは、次のことなく(いくつかの改善を適用することによって)実装できます。
find . -depth \
! -path . \
! -path ./folder1 \
! -path './folder1/*' \
! -path ./file1 \
! -path ./folder2 \
! -path ./folder2/subfolder \
! -path ./folder2/subfolder/onefile \
\( \( ! -type d -exec rm {} + \) -o \( -type d -exec rmdir {} + \) \)
./folder2
を明示的に除外することで、コマンドが./folder2/subfolder
意味のある終了状態を返すようにし、これらのディレクトリがonefile
存在しなくても保存します。
onefile
存在しないディレクトリを削除するには、追加のパターンを使用しないでください。研究--ignore-fail-on-non-empty
オプションrmdir
。 POSIXにはこのオプションは必要ありません。
私は最後の命令が厳しいとは言わないでしょう。私はそれが-regex
良いです。
答え2
これらの潜在的に破壊的な作業の場合は、手動で慎重に実行します。フルパスを含むすべてのファイルのリストを取得し、残る必要があるファイルを編集するか(またはお気に入りのテキストエディタを使用して欠落しているファイルがgrep -v
あるかどうかを確認します)。リストをフィードします(rm
リストが大きい場合は使用する必要があるかもしれません)。xargs(1)
スペースやその他の珍しい文字を含むファイル名に注意してください。