[解決済み] bashで最新のXファイル以外を削除する
質問
bashを使ったごく普通のUNIX環境で、あるディレクトリから最新のXファイル以外を削除するコマンドを実行する簡単な方法はないでしょうか?
もう少し具体的な例を挙げると、あるcronジョブが1時間ごとにディレクトリにファイル(例えば、ログファイルやtarで圧縮したバックアップ)を書き出すとします。私は、そのディレクトリ内の最も古いファイルが例えば5個以下になるまで削除する別のcronジョブを実行させる方法が欲しいです。
そして、はっきりさせておきたいのは、存在するのは1つのファイルだけで、それは決して削除されるべきものではないということです。
解決方法は?
既存の回答での問題点
-
スペースや改行が埋め込まれたファイル名を扱えない。
-
を呼び出すソリューションの場合
rm
を引用符で囲まれていないコマンド置換に直接適用します (rm `...`
を使用すると、意図しないグロビングが発生する危険性が増えます。
-
を呼び出すソリューションの場合
-
ファイルとディレクトリを区別できない (つまり、もし
ディレクトリ
が、ファイルシステムの直近に更新された5項目の中にたまたま含まれていた場合、実質的に
少ない
を適用すると、5つのファイルよりも
rm
をディレクトリに追加すると失敗します)。
wnoiseの回答 はこれらの問題を解決していますが、その解決策は GNU -特有の(そしてかなり複雑な)ものです。
ここで、プラグマティックに POSIX準拠の解決策 のみが付属しています。 1つの注意点 を埋め込んだファイル名は扱えません。 改行 - しかし、それはほとんどの人にとって現実的な問題ではないと考えています。
ちなみに、一般にパースするのが良くないとされる理由は以下のとおりです。
ls
を出力します。
http://mywiki.wooledge.org/ParsingLs
ls -tp | grep -v '/$' | tail -n +6 | xargs -I {} rm -- {}
注)このコマンドは
現在
ディレクトリ
になります。
ディレクトリを対象とする
明示的に
を使用する場合は、サブシェル (
(...)
を使用します。
cd
:
(cd /path/to && ls -tp | grep -v '/$' | tail -n +6 | xargs -I {} rm -- {})
同
は、以下のコマンドに類似して適用されます。
.
上記は
非効率的
なぜなら
xargs
を呼び出す必要があります。
rm
別途
各ファイル名に対して
.
ただし、お使いのプラットフォーム固有の
xargs
の実装により、この問題を解決できるかもしれません。
という解決策
と連携します。
GNU
xargs
を使用することです。
-d '\n'
となり、その結果
xargs
入力行を個別の引数とみなし、コマンドラインに収まるだけの引数を渡します。
一度に
:
ls -tp | grep -v '/$' | tail -n +6 | xargs -d '\n' -r rm --
注)オプション
-r
(
--no-run-if-empty
) は、確実に
rm
がある場合は呼び出されません。
入力なし
.
という解決策
で動作します。
両方
GNU
xargs
と
ビーエスディー
xargs
(を含む
macOS
) - ただし、技術的にはまだ
ではない
POSIX 準拠 - を使用することです。
-0
を処理するために
NUL
-で区切られた入力は、まず改行を
NUL
(
0x0
) の文字列も渡すことができ、(通常)すべてのファイル名
すぐに
:
ls -tp | grep -v '/$' | tail -n +6 | tr '\n' '\0' | xargs -0 rm --
説明する。
-
ls -tp
ファイルシステムの項目名を、最近更新されたものから順に表示します。-t
) が表示され、ディレクトリは末尾に/
というようにマークします (-p
).-
注意:それは
ls -tp
は常にファイル/ディレクトリを出力します。 名前 のみで、フルパスではありません。そのため、カレントディレクトリ以外のディレクトリをターゲットにするには、前述のサブシェルアプローチが必要になります ((cd /path/to && ls -tp ...)
).
-
注意:それは
-
grep -v '/$'
を省略することで、結果の一覧からディレクトリを除外します。-v
) の行で、末尾に/
(/$
).- 洞窟 : を使用しているため ディレクトリを指すシンボリックリンク は、技術的にはそれ自体がディレクトリではないので、そのようなシンボリックリンクは ない は除外されます。
-
tail -n +6
はスキップします。 5 のエントリを返し、実質的にすべての ただし 最近更新された5つのファイル。
を除外するためにN
ファイルを作成します。N+1
に渡す必要があります。tail -n +
. -
xargs -I {} rm -- {}
(およびそのバリエーション) を起動しrm
をこれらのファイル全てに適用します。もし全くマッチしない場合はxargs
は何もしない。-
xargs -I {} rm -- {}
プレースホルダーを定義する{}
は、各入力行を表す 全体として ということでrm
は、入力行ごとに一回ずつ呼び出されますが、スペースを埋め込んだファイル名は正しく処理されます。 -
--
で始まるファイル名は、すべてのケースで-
と間違われることはありません。 オプション によってrm
.
-
A バリエーション 元の問題に対する マッチしたファイルを処理する必要がある場合 個別に または シェル配列に収集される :
# One by one, in a shell loop (POSIX-compliant):
ls -tp | grep -v '/$' | tail -n +6 | while IFS= read -r f; do echo "$f"; done
# One by one, but using a Bash process substitution (<(...),
# so that the variables inside the `while` loop remain in scope:
while IFS= read -r f; do echo "$f"; done < <(ls -tp | grep -v '/$' | tail -n +6)
# Collecting the matches in a Bash *array*:
IFS=$'\n' read -d '' -ra files < <(ls -tp | grep -v '/$' | tail -n +6)
printf '%s\n' "${files[@]}" # print array elements
関連
-
[解決済み] Bashスクリプトのソースディレクトリをスクリプト自体から取得するにはどうすればよいですか?
-
[解決済み] Bashでコマンドの出力に変数を設定するにはどうすればよいですか?
-
[解決済み] あるディレクトリにあるすべてのコード行を再帰的にカウントするにはどうすればよいですか?
-
[解決済み] Bashでファイルの中身をループする
-
[解決済み] 好ましいBashのシェバングとは?
-
[解決済み] bashシェルスクリプトの全引数を伝搬させる
-
[解決済み] Bashスクリプトで、ある条件が発生したらスクリプト全体を終了させるにはどうしたらいいですか?
-
[解決済み] Bashで現在の作業ディレクトリをスクリプトのディレクトリに設定するにはどうすればよいですか?
-
[解決済み] ディレクトリをTarするが,完全な絶対パスはアーカイブに保存しない
-
[解決済み】Bashスクリプトでクリップボードにパイプを接続する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】SEDをワイルドカードで使用する場合
-
[解決済み] sed で二重引用符と単一引用符をエスケープするにはどうしたらいいですか?
-
[解決済み] スクリプトからのエラーメッセージを含むすべての端末出力をログファイルにパイプする方法
-
[解決済み] echoコマンドでパイピングが効かない [重複]。
-
[解決済み] awk で行を飛ばすにはどうしたらいいですか?
-
npm err インストールエラーの解決策
-
[解決済み] "[0: コマンドが見つかりません]" in Bash [重複].
-
[解決済み] bashの"-ne "はどういう意味ですか?
-
[解決済み] N日以上前のファイルを削除するバッチファイル
-
[解決済み] xargsがスペースを含むファイル名を扱えるようにする