Linuxで最新の10個を除くすべてのファイルを削除するにはどうすればよいですか?


49

ディレクトリをログファイルでいっぱいに管理しやすくしようとしています。毎晩、最新の10個を除くすべてを削除します。単一のコマンドでこれを行うにはどうすればよいですか?


3
logrotateを見て
knittl


@michaelディスカッションが最初に作成された場合、どうすればそのコピーを複製できますか?
dev4life

@ovaherenow "yours"?どちらの質問にもあなたの名前が載っていないので、どういう意味かわかりません。私のコメントは、他のコメントが重複していることすら示していません。しかし、それは問題ではありません-それは、リンク付きの単なるコメントです。どちらかの質問、または両方の質問に追加できます。どちらか一方を重複としてマークするのは、他の誰か(管理者)次第です。極悪非道なものは意図されておらず、知覚されるべきでもありません。どの質問が最初であったかよりも重要なのは、どの質問が最良の答えを持っていることです。ここでも、リンクはこの議論を容易にし、答えを決定しません。
マイケル

@michael wow。それは本当に奇妙です。このスレッドは私によって開かれましたが、それは明らかに私のユーザー名ではありません。しかし、私はこのスレッドについて通知を受けています。
dev4life

回答:


58

ポータブルで信頼できるソリューションについては、これを試してください:

ls -1tr | head -n -10 | xargs -d '\n' rm -f --

tail -n -10他の回答のいずれかの構文はどこでも機能しないようです(つまり、RHEL5システムでは機能しません)。

また、コマンドラインで$()または``を使用してrm

  1. ファイル名を空白で分割する
  2. コマンドラインの最大文字数制限を超えています。

xargs文字制限内で渡すことができる引数の数を自動的に把握し-d '\n'、入力の行境界でのみ分割するため、これらの問題の両方を修正します。技術的には、改行を含むファイル名で問題が発生する可能性がありますが、それはスペースを含むファイル名よりもはるかに一般的ではなく、改行を回避する唯一の方法ははるかに複雑で、おそらくperlではないにしても少なくともawkが関与します。

xargs(古いAIXシステム、おそらく?)がない場合は、ループにすることができます。

ls -1tr | head -n -10 | while IFS= read -r f; do
  rm -f "$f"
done

rmファイルごとに個別に生成されるため、これは少し遅くなりますが、上記の警告1と2を回避します(ただし、ファイル名に改行が含まれています)。


@HaukeLaging:head(1)manページから:-n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file
アイザックフリーマン

Solaris 10のオンheadxargsギブ・エラー。正しい選択肢があるhead -n 10xargs rm -f。完全なコマンドがあるls -1tr ./ | head -n 10 | xargs rm -rf
DmitrySandalov

1
これls -1trは、文字「L」ではなく、数字ONEであることに注意してください。
shonky linuxユーザー

1
改行はまれですが、extファイル名では有効な文字であることに注意してください。これは、ファイル「that」および「that \ nthing」がある場合、このスクリプトが「that \ nthing」にヒットすると、「that」を削除し、「thing」を削除できなかったときにエラーが発生し、終了することを意味します「that \ nthing」(意図したターゲット)は影響を受けません。
Synthead

1
@IsaacFreeman悪いアドバイスを削除しました、乾杯。
ウォルフ

20

スクリプトに含めるコードは

 rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)

-1(数字の1)のオプションは、安全のために、単一の行に各ファイルを印刷します。-fオプションは、rmときのために、存在しないファイルを無視するように指示ls何も返しませんが。


オリジナルのポスターはこちら。このコマンドを試しましたが、機能しません-「rm:オペランドがありません」というエラーが表示されます
-user75814

2
正しいパスを使用しましたか?明らか/path/to/your/logsに、正しいパスを入力するために構成されています。バグを見つけるには、パーツls -t /path/...ls -t /path/... | tail -n +11単独で実行し、結果が正しいかどうかを確認します。
ダニエルベーマー

1
@HaukeLagingあなたが何かおかしくなったと確信しています。+番号の前に注意してください。それは作るtail最後のn個の要素が、n番目から始まるすべての要素を印刷しません。再度チェックインすると、コマンドはすべての状況で最新の10個のファイルより古い要素のみを確実に削除するはずです。
ダニエルベー

@halo確かに、ごめんなさい。
Hauke Laging

2
私はあなたの答えは非常に危険だと思うlsあなたは、ように、ファイル名、パスではなく、プリントrm -f、現在のディレクトリ内のファイルを削除しようとします
ユルゲン・Steinblock

14

どうやら構文解析lsは悪です。

各ファイルが毎日作成され、過去10日以内に作成されたファイルを保持したい場合は、次のことができます。

find /path/to/files -mtime 10 -delete

または、各ファイルが任意に作成される場合:

find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf

5
-mtime 10 -delete正確に10日前に変更されたファイルのみを削除します。古いファイルは削除されません。-mtime +11 -delete11日以上前に変更されたファイルを削除し、過去10日間のログファイルを残します。
マルクス

1
ファイルのフルパスを取得するには、の%p代わりにの使用%Pが必要だと思いprintfます。それ以外の場合はrm -rf機能しません。
ジャロパバ

9

logrotateのようなツールがこれを行います。ログ管理がはるかに簡単になります。また、ハローが示唆するような追加のクリーンアップルーチンを含めることもできます。



1

ここから:

#! /bin/sh
# keepnewest
#
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
#
# Usage: cleanup <dir> <number of files to keep>
#
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.


if [ $# -ne 2 ]; then
  echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
  exit 1
fi

cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
  ls -t | tail -n $files_to_delete | xargs rm
  if [ $? -ne 0 ]; then
    echo "An error ocurred deleting the files"
    exit 1
  else
    echo "$files_to_delete file(s) deleted."
  fi
else
  echo "nothing to delete!"
fi

1
この答えを提供してくれてありがとう。このようなコードを提供することは有用ですが、使用方法やコードの機能に関する追加情報を提供することも役立ちます。編集ボタンを使用して、投稿に今後の改善を加えることができます。
ヒンクル

1

Bashで試すことができます:

ls -1t | (i=0; while read f; do
  if [ $i -lt 10 ]; then
    ((i++))
    continue
  else
    rm -f "$f"
  fi
done)

これにより、最新の10個のalsがスキップされ、残りが削除されます。logrotateの方が良いかもしれません。間違ったシェル関連の答えを修正したいだけです。


1

これが誰にも役立つかどうかはわかりませんが、奇妙な文字の潜在的な問題を回避lsするために、私はソートを実行してからinode削除にファイルを使用していました。

現在のディレクトリでは、変更時間に基づいて最新の10個のファイルが保持されます。

ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;


0

busybox(ルーター)にはエレガントなソリューションが必要でした。すべてのxargsまたはアレイソリューションは役に立たなかった-そのようなコマンドはありません。findおよびmtimeは、必ずしも10項目ではなく10項目について話しているため、適切な答えではありません。Espoの答えは、最短で最もクリーンで、おそらく最も一般的なものでした。

スペースのエラーと、ファイルを削除しない場合は、どちらも単純に標準的な方法で解決されます。

rm "$(ls -td *.tar | awk 'NR>7')" 2>&-

もう少し教育的なバージョン:awkを異なる方法で使用すれば、すべてを実行できます。通常、このメソッドを使用して、awkからshに変数を渡します(返します)。できないことを常に読んでいると、私は違うことを請います:ここに方法があります。

ファイル名のスペースに関して問題のない.tarファイルの例。テストするには、「rm」を「ls」に置き換えます。

eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')

説明:

ls -td *.tarすべての.tarファイルを時間でソートしてリストします。現在のフォルダー内のすべてのファイルに適用するには、「d * .tar」部分を削除します

awk 'NR>7... 最初の7行をスキップします

print "rm \"" $0 "\"" 行を作成します:rm "ファイル名"

eval それを実行する

を使用しているためrm、スクリプトでは上記のコマンドを使用しません!賢明な使用法:

(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))

ls -tコマンドを使用する場合、次のような馬鹿げた例に害はありません:touch 'foo " bar'およびtouch 'hello * world'。実際にそのような名前のファイルを作成することはありません!

サイドノート。このように変数をshに渡したい場合は、単にprintを変更します。

print "VarName="$1

変数VarNameをの値に設定します$1。複数の変数を一度に作成できます。これVarNameは通常のsh変数になり、後でスクリプトまたはシェルで通常使用できます。そのため、awkを使用して変数を作成し、それらをシェルに戻すには:

eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"

0

lsの解析は悪であることに同意します!

最後の5つのファイルのみが/srv/backupsパスに保持されていることを確認してください。

find /srv/backups -maxdepth 1 -type f -printf '%Ts\t%P\n' \
    | sort -rn \
    | tail -n +6 \
    | cut -f2- \
    | xargs -r r

0

Isaac Freemanの応答に基づいていますが、任意のディレクトリで作業しています:

ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --

次のようにプレフィックスを設定することもできます $PATH_TO_DELETE/testFi*

を使用*するPATH lsと、少なくとも「my」bashで絶対ファイル名が出力されます:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.