最も古いファイルを移動するシェルスクリプト?

最も古いファイルを移動するシェルスクリプト?

最も古いファイルの20個をあるフォルダから別のフォルダに移動するスクリプトを作成するには?フォルダから最も古いファイルをインポートする方法はありますか?

ベストアンサー1

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

代わりに、findファイルを見つけてタイムスタンプでsort並べ替えるために使用してください。たとえば、

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

これは何してるの?

まず、このコマンドは現在のディレクトリ()内のすべてのファイルとディレクトリをfind検索し、現在のディレクトリ()のサブディレクトリから検索しなかった後に印刷します。.-maxdepth 1

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

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

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

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

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

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

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

find、パイプラインの結果はsort以下を通過します。プロセスの交換whileまるで標準入力のファイルのように読み込まれるところです。入力を処理するためにwhile順番に呼び出されますread

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

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

この時点でファイル名が保存され、$file必要に応じて何でもできます。何かが完了すると、$fileステートメントwhileが繰り返され、readコマンドが再度実行され、次のチャンクと次のファイル名が抽出されます。

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

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

使用ls -tしてパイプする場合(headまたはtail何もない)ファイル名に改行文字があるファイルでは中断されます。mv $(anything)名前にスペースが含まれているファイルは破損する可能性があります。mv "$(anything)"名前の後に改行文字があるファイルは破損する可能性があります。そうreadしないと、名前-d $'\0'にスペースを含むファイルが破損します。

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

解決策

#!/usr/bin/env bash

# move to the first argument
dest="$1"

# move from the second argument or .
source="${2-.}"

# move the file count in the third argument or 20
limit="${3-20}"

while IFS= read -r -d $'\0' line ; do
    file="${line#* }"
    echo mv "$file" "$dest"
    let limit-=1
    [[ $limit -le 0 ]] && break
done < <(find "$source" -maxdepth 1 -printf '%T@ %p\0' \
    2>/dev/null | sort -z -n)

次のように電話してください。

move-oldest /mnt/backup/ /var/log/foo/ 20

最も古い20ファイルをからに移動/var/log/foo/します/mnt/backup/

ファイルが含まれているので参考にしてくださいそして目次。ファイルの場合は、通貨-type fに追加するだけです。find

ありがとう

ありがとうエンゾチップそしてパベル・タニコフこの回答が改善されました。

おすすめ記事