n개의 최신 파일을 특정 디렉토리에 복사하는 방법은 무엇입니까?

n개의 최신 파일을 특정 디렉토리에 복사하는 방법은 무엇입니까?

사용

find $dirname -printf "%T@ %Tc %p\n" | sort -n | tail -n 15

아래 디렉토리 구조에서 n번째(예제에서는 n = 15) 최신 파일을 찾을 수 있습니다 $dirname. 이제 파일을 디렉토리에 복사(또는 링크)하고 싶습니다 $current. 새로 추가된 모든 파일을 보기 위해 주기적으로 백그라운드 스크립트를 실행하고 싶습니다.

이것의 배경은 내가 rclonems 공유점에서 내 랩톱으로 디렉터리 구조를 미러링한 다음 $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 -nand를 사용했습니다 . 전체 입력을 읽어야 하는 반면 처음 15개의 파일 이름을 출력한 후 즉시 종료할 수 있습니다 .head -ntail -nheadtail

xargs -0r두 번 사용하십시오. 먼저 readlink각 파일 이름의 전체 표준 경로를 가져온 $current다음 ln.

find참고: 이를 위해서는 지원되는 버전의 , 지원되는 printf버전 , , 및 sortheadreadlinksed, 대상 디렉터리 옵션을 지원하는 버전 및 -z지원되는 버전의 가 필요합니다. 예를 들어 이들 모두의 GNU 버전이 있습니다.ln-txargs-0

또한 다른 버전의 sed에서는 for tab이 대괄호 표현식 내에서 작동하는지 기억이 나지 않지만 \tGNU sed에서는 확실히 작동합니다.

Linux를 실행하고 있다면 coreutils, findutils, sed 등의 GNU 버전만 있으면 됩니다. (GNU가 아닌 버전을 설치하는 등 정말 이상하고 설명할 수 없는 미친 짓을 하지 않는 한)

답변2

zsh에서는 많은 복잡한 find호출이 비밀스럽지만 짧은 것으로 변환됩니다. zsh의 사용자 정의 정렬은 다른 방법에 비해 특히 편리합니다. 다음 zsh 명령은 다음 15개의 최신 일반 파일을 나열합니다 $dirname.

print -rC1 -- $dirname/**/*(.Nom[1,15])

**하다재귀 와일드카드. 마지막 괄호 안의 문자는 다음과 같습니다.글로벌 예선: 일치하는 파일이 없을 때 오류를 방지하기 위해 .일반 파일을 선택하고 , 수정 시간순(최근 파일부터)으로 정렬한 후 상위 15개 파일을 선택합니다.Nom[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에 이 스크립트의 실행을 추가하세요.

관련 정보