사용
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
두 번 사용하십시오. 먼저 readlink
각 파일 이름의 전체 표준 경로를 가져온 $current
다음 ln
.
find
참고: 이를 위해서는 지원되는 버전의 , 지원되는 printf
버전 , , 및 sort
head
readlink
sed
, 대상 디렉터리 옵션을 지원하는 버전 및 -z
지원되는 버전의 가 필요합니다. 예를 들어 이들 모두의 GNU 버전이 있습니다.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에 이 스크립트의 실행을 추가하세요.