"쉬운" 솔루션

"쉬운" 솔루션

문맥

tar.gz 파일을 생성하고 이를 헤드리스 Linux 가상 머신의 dropbox 폴더로 전송하는 백업 스크립트를 실행하고 있습니다.

질문

스킴에 따라 이름이 지정된 파일 중 가장 오래된 파일을 검색하는 스크립트를 만드는 방법을 모르겠습니다 /root/Dropbox/apache2-backup-%Y-%m-%d-%H-%M.

/root/Dropbox-archive/그런 다음 Dropbox에 공간이 2GB밖에 없기 때문에 이 파일을 폴더로 옮기고 싶습니다 .

답변1

"쉬운" 솔루션

ls -1 /Dropbox/apache2-backup-*이름, 즉 날짜별로 알파벳순으로 정렬해야 합니다(날짜는 가장 중요한 숫자가 왼쪽에 오도록 형식화되어 있으므로). 그런 다음 파이프를 통해 가장 오래된 파일을 가져올 수 있습니다 head -1(파일 이름에 줄 바꿈이 없다고 가정). 일반적으로 파이핑을 사용하는 ls것은 좋지 않은 생각이지만 이 경우 파일 이름에 특수 문자가 없다는 것을 알고 있으므로 괜찮습니다.

mv "$(ls -1 /Dropbox/apache2-backup-* | head -1)" /root/Dropbox-archive/

실수로 파일을 덮어쓰는 일이 없도록 mv --no-clobber( 또는 )를 대신 사용하는 것이 좋습니다 .mv -n

"올바른" 솔루션

특수 문자가 정말 걱정된다면 다음을 대신 사용할 수 있습니다.

to_move="$(find /Dropbox -maxdepth 1 -type f -name 'apache2-backup-*' -print0 | sort -z | tr '\0\n' '\n\0' | head -1 | tr '\0\n' '\n\0')"
mv "$to_move" /root/Dropbox-archive/

설명하다

  • find /Dropbox -maxdepth 1 -type f -name 'apache2-backup-*' -print0: 패턴( )과 일치하는 하위 디렉터리를 입력하지 않고 일반 파일( -type f) 을 반환합니다 . 줄바꿈이 아닌 널 문자로 구분하세요 ./Dropbox-maxdepth 1-name 'apache2-backup-*'-print0
  • | sort -z:유형널 문자를 기반으로 합니다(모든 유형이 이를 수행할 수 있는 것은 아닙니다).
  • | tr '\0\n' '\n\0':교환Null과 개행 문자는 헤드에서 처리됩니다.
  • | head -1: 첫 번째 줄로 돌아갑니다.
  • | tr '\0\n' '\n\0': null 값과 개행 문자를 다시 바꿉니다.
  • mv "$to_move" /root/Dropbox-archive/: 움직여보자!

또는 한 줄로:

mv "$(find /Dropbox -maxdepth 1 -type f -name 'apache2-backup-*' -print0 | sort -z | tr '\0\n' '\n\0' | head -1 | tr '\0\n' '\n\0')" /root/Dropbox-archive/

답변2

가장 오래된 것만 옮기는 경우하나, 이것을 사용하십시오 :

_mv(){ mv -- "$1" /root/Dropbox-archive/; }
_mv /Dropbox/apache2-backup-*

하지만 제목에는 그런 내용이 나와 있지 않습니다.


처리 ls출력이나쁜 생각, 더 나은 접근 방식은 다음과 같습니다.

if [ "$BASH" ]; then
# If you happen to use bash or any other shell that has some similar array:
move_first_things(){ mv -- "${@:0:50}" /root/Dropbox-archive/; }
else # Unfortunate POSIX way
# As long as copy-pasting is acceptable, loop-unrolling with
# `mv -- "$1" "$2" "$3"... /root/Dropbox-archive/` is better since it calls `mv` less.
move_first_things(){
    local max=50 count=0
    while [ "$count" -lt "$max" ]; do
        mv -- "$1" /root/Dropbox-archive/
        shift
        : $((count = count + 1))
    done
}
fi

출력은 다음과 같은 와일드카드로 인해 정렬됩니다 ls.

move_first_things /Dropbox/apache2-backup-*

폴리스티렌: 이것은 실제로 외부 프로그램(mikeserv,여기에 설명되어 있습니다). 약간의 주의와 약간의 혼란만 더해지면 사람들은 안전하게 작업을 수행할 수 있습니다. 하지만 이 경우에도 여전히 예쁜 파일 이름을 사용하겠습니다.

폴리페닐렌 설파이드:don_crist가 일부 zshism을 언급했습니다. zsh는 함수, 매개변수 확장, 배열과 같은 익명 기능을 훌륭하게 지원합니다. 여전히 파일 이름 방식을 사용하면( bash그러한 정렬 연산자가 없기 때문에) 전체 내용을 다음과 같이 작성할 수 있습니다 baks=( /Dropbox/apache2-backup-* ); mv "$baks" /root/Dropbox-archive/(첫 번째 멤버만 제공하는 배열 참조) mv "${baks[@]:0:50}" /root/Dropbox-archive/. 또는 여러 가지에 대해 실제로는 해당 래퍼보다 더 좋아 보입니다 . 기능이 더 좋습니다.

답변3

(   IFS=/                                      # split on /
    set -ef /Dropbox/apache2-backup*           # set arg array to last glob
    for    f in    $(\ls -rtd "$@";echo /)     # iterate over sorted/split array
    do     [ -z "${f##D*}" ]  ||               # ignore dirname
           mv "${1%/*}/${f%?}" \
              "/root${1%/*}-archive"           # do sorted mv
    done                                       # do && break to do only one mv
)

어떤 이유로든 사람들은 를 사용하여 매개변수 목록을 안정적으로 정렬할 수 없다고 생각하는 것 같습니다 ls. 내 생각엔 이 사람들이 개행 문자로 경로명을 분리하려고 하기 때문인 것 같습니다. 그러나 문제는 경로명이 줄 바꿈으로 구분되지 않는다는 것입니다. 결코 그런 적이 없습니다. 경로 이름 구분 기호 /- 경로 이름 구분 기호이므로 개행 문자는 혼란을 야기할 뿐입니다. 출력을 안정적으로 구문 분석하려면 ls출력을 올바르게 분할해야 합니다.

답변4

질문은 가장 오래된 파일을 지정했습니다. ls -rt수정 시간을 기준으로 오래된 파일부터 정렬하여 파일을 나열합니다. 이 답변은 백업 파일을 식별하는 접두사 이외의 파일 이름 형식을 사용하지 않습니다. 여기에서는 파일 이름의 날짜 부분이 고려되지 않습니다.

mv "$(ls -tr /root/Dropbox/apache2-backup-*| head -1)" /root/Dropbox-archive/

파일 시간을 기준으로 정렬하는 것은 파일 이름을 기준으로 정렬하는 것보다 낫지 않으며 그 반대도 마찬가지입니다. 이는 대체로 개인 취향이며 상황과 문화에 따라 다릅니다.

"두 경우 모두, 그리고 대부분의 경우 아래와 같이 명령 확장을 큰따옴표로 묶는 것이 더 안전합니다. "$( ... )"이렇게 하면 파일 이름을 제외하고 백업 파일 파일 이름 등의 모든 특수 문자(공백, 구두점, 탭)를 처리합니다. 개행 문자를 포함합니다.

관련 정보