重複の可能性:
最も古いファイルを移動するシェルスクリプト?
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
表します。
-z
NULL を改行文字ではなく行終端として扱います。-n
数値順に並べ替え
1970年以降の秒数は常に増加するため、タイムスタンプの数が最も少ないファイルが必要です。最初の結果sort
は、最も低い番号のタイムスタンプを含む行になります。残りはファイル名を抽出するだけです。
find
、パイプラインの結果はsort
以下を通過します。プロセスの交換to read
、標準入力からファイルに読み込まれます。
read
変数をスペースに設定した文脈では、スペースはIFS
区切り文字として不適切に解釈されないことを意味します。エスケープ拡張を無効にし、行末の区切り文字をNULLにしてパイプの出力と一致させることがread
わかります。-r
-d $'\0'
find
sort
最初のデータブロックは、タイムスタンプとスペースが続く最も古いディレクトリパスを表し、変数として読み込まれます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 属性を使用します。sort
head
tail
ls
答え3
以下を試してください。
rm $(ls -t1 | tail -n 1)