X日より古いファイルのみを含むディレクトリを見つける方法は?

X日より古いファイルのみを含むディレクトリを見つける方法は?

X日を過ぎたファイル(作成/変更)のみを含むディレクトリを削除する必要があります。

これを試してみましたが、今日のファイルのみが表示され、再帰的には表示されません。

for d in *; do   
  find "$d" -mindepth 1 -mtime -180 -print -quit | | grep -q . ||     
  echo rm -rf "$d";
done

答え1

あなたが欲しい」X日より古いファイルのみを含むディレクトリを削除する」。

これを処理する1つの方法は次のとおりです。

  • リーフノードから始めて、各ディレクトリに対して次のようにします。
  • サブディレクトリの数を数えます。 0以外の場合はスキップします。
  • ディレクトリ以外の項目の数を計算します。 0の場合はスキップします。
  • 基準(年齢)と一致する文書数の計算
  • 両方のファイルの番号が同じ場合は、そのディレクトリを削除してください。

このソリューションには、GNUまたは、findおよびを理解する代替バージョンが必要です。-mindepth-maxdepthprintf

この特定の例では、(日)Xに設定されています。180

days=180
find ./* -depth -type d -exec sh -c '
    [ -z "'"$days"'" ] && exit 1
    printf "Considering directory: %s\n" "$1"

    dirs=$(find "$1" -mindepth 1 -maxdepth 1 -type d -print | xargs)
    if [ -n "$dirs" ]
    then
        printf "Found child directories: (%s)\n" "$dirs"
        exit 0
    fi

    all=$(find "$1" -maxdepth 1 ! -type d -printf x | wc -c)
    got=$(find "$1" -maxdepth 1 -type f -mtime +'"$days"' -printf x | wc -c)
    printf "Found %d item(s) and matched %d\n" $all $got

    if [ $all -gt 0 ] && [ $all -eq $got ]
    then
        printf "Delete directory: %s\n" "$1"
        : rm -rf "$1"
    fi
' _ {} \;

変数の2つの用途を囲む見かけ上の奇妙な引用符は、スクリプトの残りの部分が一重引用符$daysで囲まれているのに対し、変数は二重引用符で囲まれて値を決定できるようにするためです。'..start of script..' "$variable" '..remainder of script..'ある種の引用符の終わりと別の種類の引用符の先頭との間にスペースがないことを理解するのは簡単かもしれません。

printfコードを自動的に実行するには、次の文を削除してください。削除する準備ができたら、:前のコロン()を削除してください。rm -rf

答え2

これは、そのファイルの./a/b埋め込み./a最新のファイルに180日より古い非ディレクトリファイルを含まない最も浅いディレクトリがあると仮定した場合のバリエーションです。./a./a/bファイルのない最も浅いディレクトリのみを一覧表示します。だから、あなたは使用することができます私の答えGNUシステムの場合:

find . -type d -print0 -o -mtime -180 -printf 'f/%h\0' |
  LC_ALL=C sort -zru |
  LC_ALL=C awk -F/ -v RS='\0' '
    function parent(path) {
      sub("/[^/]*$", "", path)
      return path
    }
    $1 == "f" {
      sep = path = ""
      for (i = 2; i <= NF; i++) {
        black[path = path sep $i]
        sep = FS
      }
      next
    }
    ! ($0 in black) && ($0 == "." || parent($0) in black)'

目次を黒く塗ったらどうでしょうか?どのディレクトリ以外のファイルは、そのファイルを黒で表示します。180日以内にディレクトリ以外のすべてのファイル

または、最も近いファイルが見つかった場合は、配列からディレクトリを削除するバリアントです。

find . -type d -printf '%p/\0' -o -mtime -180 -printf '%h/f\0' |
  LC_ALL=C sort -zu |
  LC_ALL=C awk -F/ -v RS='\0' '
    function parent(path) {
      sub("[^/]+/?$", "", path)
      return path
    }
    /\/$/ {dir[$0]; next}
    {
      path = ""
      for (i = 1; i <= NF; i++)
        delete dir[path = path $i FS]
    }
    END {
      for (path in dir) if (! (parent(path) in dir)) print path
    }'

(最も浅いものではありません)両方が必要な場合は簡単になります./a./a/b

find . -type d -printf '%p/\0' -o -mtime -180 -printf '%h/f\0' |
  LC_ALL=C sort -zu |
  LC_ALL=C awk -F/ -v RS='\0' '
    /\/$/ {dir[$0]; next}
    {
      path = ""
      for (i = 1; i <= NF; i++)
        delete dir[path = path $i FS]
    }
    END {
      for (path in dir) print path
    }'

これを削除するには、to-v ORS='\0'を追加してawkNULで区切って印刷し、toにパイプします。ただし、ほとんどの実装では、返された場合(現在のディレクトリに最近のファイルがない場合)、何も拒否されることxargs -r0 rm -rfに注意してください。./rm

これらの方法はfindディレクトリツリー全体を一度だけ実行してナビゲートするため、最も近いファイルを見つけるために各ディレクトリのコンテンツをクロールする簡単な方法よりも効率的です。

効率が低い方法は次のとおりですzsh

print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/**/*(NDm-180Y1^/)'])

(含まれていませんが、以下を使用して.リストに追加できます。{.,**/*}(...)

現在のディレクトリのサブディレクトリのみを検討したい場合、このアプローチはより効率的で(上記の方法は最初の一致で停止するためY1)、短くて簡単になります。

print -rC1 -- *(ND/^e['()(($#)) $REPLY/**/*(NDm-180Y1^/)'])

.*1を回避策として使用します。一部のシェルでは、拡張に.およびが含まれているため、..災害的な結果をもたらす可能性があるためですrm -rf .*。有効な(欠陥のないシェル)組み込みrm機能を使用すると、現在の作業ディレクトリを受け入れて消去できます。zshzmodload zsh/filesrm -rf ./

関連情報