使用
find $dirname -printf "%T@ %Tc %p\n" | sort -n | tail -n 15
以下のディレクトリ構造では、n番目(例ではn = 15)の最新のファイルを見つけることができます$dirname
。これで、ファイルをディレクトリにコピー(またはリンク)したいと思います$current
。新しく追加されたすべてのファイルを表示するために定期的にバックグラウンドスクリプトを実行したいと思います。
これの背景は、私がrclone
ms共有ポイントから私のラップトップにディレクトリ構造をミラーリングしてから、$current
最近変更されたn個のファイルをすべて表示するディレクトリが欲しかったということです。
答え1
次のbashスクリプトを実行してみてくださいcron
。
#!/bin/bash
# exit on any error
set -e
set -o pipefail
# defaults for the options
n=15
dirname='/default/path/to/your/files'
current='/default/path/to/the/current/dir'
while getopts ':n:d:c:' opt ; do
case "$opt" in
n) n="$OPTARG";;
d) dirname="$OPTARG";;
c) current="$OPTARG";;
:) echo "Error: '-$OPTARG' requires an argument" >&2 ; exit 1 ;;
*) echo "Error: unknown option '-$OPTARG'" >&2 ; exit 1 ;;
esac
done
if [ ! -d "$current" ] ; then
if ! mkdir -p "$current" ; then
echo "Error: '$current' can't be created or already exists and isn't a directory" >&2
exit 1
fi
fi
rm -f "$current"/*
# alternatively, to delete only symlinks in $current:
# find -H "$current/" -maxdepth 1 -type l -delete
find "$dirname/" -type f -printf "%T@\t%p\0" |
sort -z -r -n |
head -z -n "$n" |
sed -z -e 's/^[^\t]*\t//' |
xargs -0r readlink -e -z |
xargs -0r ln -s -t "$current/"
これはファイル名間の区切り文字としてNULを使用するため、有効な文字を含むファイル名で機能します(NULはただパス/ファイル名に無効な文字が含まれています)。
パイプラインのスクリプトはsed
タイムスタンプフィールドを削除します(最大および含む)。最初TAB 文字 - TAB はファイル名で有効な文字であるため必要です。sed
代わりにここを使用できますcut -z -f2-
。
私は代わりに少し速いのでsort -r -n
andを使用しました。入力全体を読み取る必要がありますが、最初の15個のファイル名を出力してすぐに終了できます。head -n
tail -n
head
tail
xargs -0r
2回使用してください。まず、readlink
各ファイル名の完全な標準パスを取得して$current
からln
。
find
注:これには、サポートされているバージョン、サポートされているバージョン、、および、ターゲットディレクトリオプションをサポートするバージョン、およびprintf
サポートされているバージョンが必要です。たとえば、これらすべてのGNUバージョンがあります。sort
head
readlink
sed
-z
ln
-t
xargs
-0
また、他のバージョンの sed では for tab が角かっこ式内で動作するかどうかは覚えていませんが、\t
GNU sed では確実に動作します。
Linuxを実行している場合は、coreutils、findutils、sedなどのGNUバージョンのみが必要です。 (GNU以外のバージョンをインストールするなど、本当に奇妙で説明できないクレイジーなことをしない限り)
答え2
zshでは、多くの複雑なfind
呼び出しが秘密ですが短いものに変換されます。 zshのカスタムソートは他の方法と比較して特に便利です。次のzshコマンドは、次の15の最新の一般ファイルを一覧表示します$dirname
。
print -rC1 -- $dirname/**/*(.Nom[1,15])
**
する再帰ワイルドカード。最後の括弧内の文字は次のとおりです。グローバル予選:一致するファイルが存在しないときにエラーを防ぐために.
通常のファイルを選択し、修正時間順(最近のファイルから)に並べ替えて、上位15個のファイルを選択します。N
om
[1,15]
これはコマンドラインのワイルドカード拡張であるため、ファイル名のシェル特殊文字について心配する必要はありません。で始まる場合は、$dirname
前にダッシュがオプションとして解釈されることを心配する必要があります-
。
たとえば、以下は、へのインクルードrecent
ポインタを更新するための単純な(テストされていない)コードですeverything
。このコードは、名前の競合があるときにファイル名にサフィックスを追加します。
#!/usr/bin/env zsh
set -e
recent=(/everything/**/*(.Nom[1,15]))
rm -f /recent/*(@N)
for file in $recent; do
target=/recent/$file:t
i=1
while [[ -e $target ]]; do
target=$file:t:r-$i
if [[ -n $file:e ]]; then target+=.$file:e; fi
((++i))
done
ln -s -- $file $target
done
サフィックス:t
、:r
:e
歴史拡張修飾子ファイル名から、それぞれデフォルト名(tail)、拡張子のない名前(root)、および(最後の)拡張子を抽出します。
答え3
次のコマンドをスクリプトファイルに入れます。
#! /bin/bash
current="/your/absolute/path"
rm -rf "${current}"
mkdir -p "${current}"
while read FILENAME; do
ln -s "${FILENAME}" "${current}"
done < <(find "${current}" -printf "%T@ %p\n" | sort -n | tail -3 | cut -d " " -f 2-)
それから:
crontabにこのスクリプトの実行を追加します。