最も古いファイルの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
表します。
-z
NULL を改行文字ではなく行終端として扱います。-n
数値順に並べ替え
1970年以降の秒数は常に増加するため、タイムスタンプの数が最も少ないファイルが必要です。最初の結果sort
は、最も低い番号のタイムスタンプを含む行になります。残りはファイル名を抽出するだけです。
find
、パイプラインの結果はsort
以下を通過します。プロセスの交換while
まるで標準入力のファイルのように読み込まれるところです。入力を処理するためにwhile
順番に呼び出されますread
。
read
変数をスペースに設定した文脈では、スペースはIFS
区切り文字として不適切に解釈されないことを意味します。エスケープ拡張を無効にし、行末の区切り文字をNULLにしてパイプの出力と一致させることがread
わかります。-r
-d $'\0'
find
sort
最初のデータブロックは、タイムスタンプとスペースが先頭にある最も古いファイルパスを表し、変数として読み込まれます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