特定のディレクトリから最も古いディレクトリを削除する方法は? [コピー]

特定のディレクトリから最も古いディレクトリを削除する方法は? [コピー]

重複の可能性:
最も古いファイルを移動するシェルスクリプト?

xバックアップする必要がある他のディレクトリを保存するバックアップディレクトリがあります。別のディレクトリがバックアップに移動される前に実行する必要があります。ディレクトリ数に達したことを確認しx、到達すると最も古いディレクトリを削除します。

これはスクリプトで行う必要がありますbash

答え1

ls次の出力を解析します。信頼できない

代わりに を使用してfindディレクトリを検索し、sortタイムスタンプで並べ替えます。たとえば、

IFS= read -r -d $'\0' line < <(find . -maxdepth 1 -type d -printf '%T@ %p\0' \ 
    2>/dev/null | sort -z -n)
file="${line#* }"
# do something with $file here

これは何してるの?

まず、このコマンドは現在のディレクトリ()のすべてのディレクトリをfind探します。ただし、現在のディレクトリ()のサブディレクトリであるすべてのディレクトリは検索されません。次に、次を印刷します。.-maxdepth 1

  • タイムスタンプ
  • スペース
  • ファイルの相対パス
  • ヌル文字

タイムスタンプが重要です。書式%T@指定子は、ファイルの「最後の変更時間」(mtime)を表すものと、小数秒を含む「1970年以降の秒数」を表す-printfと区別されます。T@

空白は任意の区切り文字にすぎません。ファイルのフルパスは後で参照できるようにするためのものであり、NULL文字はファイル名に無効な文字なので、ファイルパスの末尾に到達したことを確認できるようにする終端者です。文書。

2>/dev/nullユーザーがアクセスできないファイルを除外するように含めましたが、そのファイルが除外されたというエラーメッセージは表示されません。

このコマンドの結果findは、現在のディレクトリのすべてのディレクトリのリストです。リストは にパイプされ、次をsort表します。

  • -zNULL を改行文字ではなく行終端として扱います。
  • -n数値順に並べ替え

1970年以降の秒数は常に増加するため、タイムスタンプの数が最も少ないファイルが必要です。最初の結果sortは、最も低い番号のタイムスタンプを含む行になります。残りはファイル名を抽出するだけです。

find、パイプラインの結果はsort以下を通過します。プロセスの交換to read、標準入力からファイルに読み込まれます。

read変数をスペースに設定した文脈では、スペースはIFS区切り文字として不適切に解釈されないことを意味します。エスケープ拡張を無効にし、行末の区切り文字をNULLにしてパイプの出力と一致させることがreadわかります。-r-d $'\0'findsort

最初のデータブロックは、タイムスタンプとスペースが続く最も古いディレクトリパスを表し、変数として読み込まれますline。次に、パラメータの置換式と共に使用すると、#*文字列の先頭から最初のスペースを含むすべての文字をnullに置き換えます。これにより、修正タイムスタンプが削除され、ファイルのフルパスのみが残ります。

この時点で、ファイル名はに保存され$fileますrm -rf "$file"

もっと簡単な方法はありませんか?

いいえ。より簡単なアプローチには欠陥があります。

andを使用してls -tパイプすると、tailファイル名に改行が含まれているファイルが中断されます。rm $(anything)名前にスペースが含まれているファイルは破損する可能性があります。rm "$(anything)"名前の後に改行文字があるファイルは破損する可能性があります。

より簡単な方法で十分であると確信する特定の状況があるかもしれませんが、可能であれば、そのような仮定をスクリプトに書き込むべきではありません。

編集する

#!/usr/bin/env bash

dir="$1"
min_dirs=3

[[ $(find "$dir" -maxdepth 1 -type d | wc -l) -ge $min_dirs ]] &&
IFS= read -r -d $'\0' line < <(find "$dir" -maxdepth 1 -printf '%T@ %p\0' 2>/dev/null | sort -z -n)
file="${line#* }"
ls -lLd "$file"

ディレクトリの数を最初に確認するので、問題に対するより完全なソリューションです。

答え2

次のようなものを使用できます。

#!/bin/sh    
keep=3

while [ `ls -1 | wc -l` -gt $keep ]; do
    oldest=`ls -c1 | head -1`
    echo "remove $oldest"
    rm -rf $oldest
done

使用する方がfind . -type d -maxdepth 1良いかもしれませんがls。これは、ディレクトリに使用する命名パターンによって異なります。自然に名前で正しくソートされている場合、またはfindを使用して、最も古い/最新のディレクトリをインポートできます。この方法では、ソートに ctime 属性を使用します。sortheadtaills

答え3

以下を試してください。

rm $(ls -t1 | tail -n 1)

関連情報